diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..0e57cb0b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +*.a +*.o +*.o.* +*.d +*.def +*.dll +*.dylib +*.exe +*.exp +*.gcda +*.gcno +*.h.c +*.ilk +*.lib +*.pc +*.pdb +*.so +*.so.* +*.swp +*.ver +*.version +*.ptx +*.ptx.c +*_g +\#* +.\#* +/.config +/.version +/ffmpeg +/ffplay +/ffprobe +/config.asm +/config.h +/coverage.info +/avversion.h +/lcov/ +/src +/mapfile diff --git a/.travis.yml b/.travis.yml index 40f01f94c..63f2051cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ addons: compiler: - clang - gcc +matrix: + exclude: + - os: osx + compiler: gcc cache: directories: - ffmpeg-samples diff --git a/Changelog b/Changelog index a8d4c29e9..61075b339 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,45 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. +version : +- Bitstream filters for editing metadata in H.264, HEVC and MPEG-2 streams +- Dropped support for OpenJPEG versions 2.0 and below. Using OpenJPEG now + requires 2.1 (or later) and pkg-config. +- VDA dropped (use VideoToolbox instead) +- MagicYUV encoder +- Raw AMR-NB and AMR-WB demuxers +- TiVo ty/ty+ demuxer +- Intel QSV-accelerated MJPEG encoding +- PCE support for extended channel layouts in the AAC encoder +- native aptX encoder and decoder +- Raw aptX muxer and demuxer +- NVIDIA NVDEC-accelerated H.264, HEVC, MPEG-1/2/4, VC1, VP8/9 hwaccel decoding +- Intel QSV-accelerated overlay filter +- mcompand audio filter +- acontrast audio filter +- OpenCL overlay filter +- video mix filter +- video normalize filter +- audio lv2 wrapper filter +- VAAPI VP8 decoding +- AMD AMF H.264 and HEVC encoders +- video fillborders filter +- video setrange filter +- nsp demuxer +- support LibreSSL (via libtls) +- AVX-512/ZMM support added +- Dropped support for building for Windows XP. The minimum supported Windows + version is Windows Vista. +- deconvolve video filter +- entropy video filter +- hilbert audio filter source +- aiir audio filter +- aiff: add support for CD-ROM XA ADPCM +- Removed the ffserver program +- Removed the ffmenc and ffmdec muxer and demuxer +- VideoToolbox HEVC encoder and hwaccel + + version 3.4: - deflicker video filter - doubleweave video filter diff --git a/MAINTAINERS b/MAINTAINERS index 9027ed584..e5839261a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29,9 +29,6 @@ ffplay: ffprobe: ffprobe.c Stefano Sabatini -ffserver: - ffserver.c Reynaldo H. Verdejo Pinochet - Commandline utility code: cmdutils.c, cmdutils.h Michael Niedermayer @@ -158,7 +155,7 @@ Codecs: cpia.c Stephan Hilb crystalhd.c Philip Langdale cscd.c Reimar Doeffinger - cuvid.c Timo Rothenpieler + cuviddec.c Timo Rothenpieler dca* foo86 dirac* Rostislav Pehlivanov dnxhd* Baptiste Coudurier @@ -170,6 +167,7 @@ Codecs: eacmv*, eaidct*, eat* Peter Ross evrc* Paul B Mahol exif.c, exif.h Thilo Borgmann + exr.c Martin Vignali ffv1* Michael Niedermayer ffwavesynth.c Nicolas George fifo.c Jan Sebechlebsky @@ -212,7 +210,7 @@ Codecs: msrle.c Mike Melanson msvideo1.c Mike Melanson nuv.c Reimar Doeffinger - nvenc* Timo Rothenpieler + nvdec*, nvenc* Timo Rothenpieler opus* Rostislav Pehlivanov paf.* Paul B Mahol pcx.c Ivo van Poorten @@ -244,8 +242,7 @@ Codecs: txd.c Ivo van Poorten vc2* Rostislav Pehlivanov vcr1.c Michael Niedermayer - vda_h264_dec.c Xidorn Quan - videotoolboxenc.c Rick Kern + videotoolboxenc.c Rick Kern, Aman Gupta vima.c Paul B Mahol vorbisdec.c Denes Balatoni, David Conrad vorbisenc.c Oded Shimon @@ -272,7 +269,7 @@ Hardware acceleration: vaapi* Gwenole Beauchesne vaapi_encode* Mark Thompson vdpau* Philip Langdale, Carl Eugen Hoyos - videotoolbox* Rick Kern + videotoolbox* Rick Kern, Aman Gupta libavdevice @@ -587,6 +584,7 @@ FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8 Ganesh Ajjanagadde C96A 848E 97C3 CEA2 AB72 5CE4 45F9 6A2D 3C36 FB1B Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4 Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368 +James Almer 7751 2E8C FD94 A169 57E6 9A7A 1463 01AD 7376 59E0 Jean Delvare 7CA6 9F44 60F1 BDC4 1FD2 C858 A552 6B9B B3CD 4E6A Loren Merritt ABD9 08F4 C920 3F65 D8BE 35D7 1540 DAA7 060F 56DE Lou Logan 7D68 DC73 CBEF EABB 671A B6CF 621C 2E28 82F8 DC3A diff --git a/Makefile b/Makefile index 642651d4c..9defddebf 100644 --- a/Makefile +++ b/Makefile @@ -45,12 +45,11 @@ FF_DEP_LIBS := $(DEP_LIBS) FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS) $(TOOLS): %$(EXESUF): %.o - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) + $(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/cws2fws$(EXESUF): ELIBS = $(ZLIB) tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS) tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS) @@ -128,21 +127,18 @@ install-data: $(DATA_FILES) $(Q)mkdir -p "$(DATADIR)" $(INSTALL) -m 644 $(DATA_FILES) "$(DATADIR)" -uninstall: uninstall-libs uninstall-headers uninstall-data +uninstall: uninstall-data uninstall-headers uninstall-libs uninstall-pkgconfig uninstall-data: $(RM) -r "$(DATADIR)" clean:: $(RM) $(CLEANSUFFIXES) - $(RM) $(CLEANSUFFIXES:%=compat/msvcrt/%) - $(RM) $(CLEANSUFFIXES:%=compat/atomics/pthread/%) - $(RM) $(CLEANSUFFIXES:%=compat/%) + $(RM) $(addprefix compat/,$(CLEANSUFFIXES)) $(addprefix compat/*/,$(CLEANSUFFIXES)) $(RM) -r coverage-html $(RM) -rf coverage.info coverage.info.in lcov -distclean:: - $(RM) $(DISTCLEANSUFFIXES) +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 \ @@ -155,6 +151,7 @@ endif config: $(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION) +build: all alltools examples testprogs check: all alltools examples testprogs fate include $(SRC_PATH)/tests/Makefile @@ -170,4 +167,5 @@ $(sort $(OBJDIRS)): # so this saves some time on slow systems. .SUFFIXES: -.PHONY: all all-yes alltools check *clean config install* testprogs uninstall* +.PHONY: all all-yes alltools build check config testprogs +.PHONY: *clean install* uninstall* diff --git a/README.md b/README.md index 7d5a7efe9..447347c70 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,6 @@ such as audio, video, subtitles and related metadata. * [ffplay](https://ffmpeg.org/ffplay.html) is a minimalistic multimedia player. * [ffprobe](https://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect multimedia content. -* [ffserver](https://ffmpeg.org/ffserver.html) is a multimedia streaming server - for live broadcasts. * Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`. ## Documentation diff --git a/RELEASE b/RELEASE index 2f4b60750..9b601acc0 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -3.4 +3.4.git diff --git a/RELEASE_NOTES b/RELEASE_NOTES deleted file mode 100644 index d649c77bd..000000000 --- a/RELEASE_NOTES +++ /dev/null @@ -1,15 +0,0 @@ - - ┌───────────────────────────────────────┐ - │ RELEASE NOTES for FFmpeg 3.4 "Cantor" │ - └───────────────────────────────────────┘ - - The FFmpeg Project proudly presents FFmpeg 3.4 "Cantor", about 6 - months after the release of FFmpeg 3.3. - - A complete Changelog is available at the root of the project, and the - complete Git history on http://source.ffmpeg.org. - - We hope you will like this release as much as we enjoyed working on it, and - as usual, if you have any questions about it, or any FFmpeg related topic, - feel free to join us on the #ffmpeg IRC channel (on irc.freenode.net) or ask - on the mailing-lists. diff --git a/VERSION b/VERSION deleted file mode 100644 index 2f4b60750..000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.4 diff --git a/compat/cuda/dynlink_loader.h b/compat/cuda/dynlink_loader.h index 7d2c87449..fa43782c9 100644 --- a/compat/cuda/dynlink_loader.h +++ b/compat/cuda/dynlink_loader.h @@ -59,29 +59,29 @@ #define LOAD_LIBRARY(l, path) \ do { \ if (!((l) = dlopen(path, RTLD_LAZY))) { \ - av_log(NULL, AV_LOG_ERROR, "Cannot load %s\n", path); \ + av_log(logctx, AV_LOG_ERROR, "Cannot load %s\n", path); \ ret = AVERROR_UNKNOWN; \ goto error; \ } \ - av_log(NULL, AV_LOG_TRACE, "Loaded lib: %s\n", path); \ + av_log(logctx, AV_LOG_TRACE, "Loaded lib: %s\n", path); \ } while (0) #define LOAD_SYMBOL(fun, tp, symbol) \ do { \ if (!((f->fun) = (tp*)dlsym(f->lib, symbol))) { \ - av_log(NULL, AV_LOG_ERROR, "Cannot load %s\n", symbol); \ + av_log(logctx, AV_LOG_ERROR, "Cannot load %s\n", symbol); \ ret = AVERROR_UNKNOWN; \ goto error; \ } \ - av_log(NULL, AV_LOG_TRACE, "Loaded sym: %s\n", symbol); \ + av_log(logctx, AV_LOG_TRACE, "Loaded sym: %s\n", symbol); \ } while (0) #define LOAD_SYMBOL_OPT(fun, tp, symbol) \ do { \ if (!((f->fun) = (tp*)dlsym(f->lib, symbol))) { \ - av_log(NULL, AV_LOG_DEBUG, "Cannot load optional %s\n", symbol); \ + av_log(logctx, AV_LOG_DEBUG, "Cannot load optional %s\n", symbol); \ } else { \ - av_log(NULL, AV_LOG_TRACE, "Loaded sym: %s\n", symbol); \ + av_log(logctx, AV_LOG_TRACE, "Loaded sym: %s\n", symbol); \ } \ } while (0) @@ -187,7 +187,7 @@ static inline void nvenc_free_functions(NvencFunctions **functions) } #ifdef AV_COMPAT_DYNLINK_CUDA_H -static inline int cuda_load_functions(CudaFunctions **functions) +static inline int cuda_load_functions(CudaFunctions **functions, void *logctx) { GENERIC_LOAD_FUNC_PREAMBLE(CudaFunctions, cuda, CUDA_LIBNAME); @@ -210,7 +210,7 @@ static inline int cuda_load_functions(CudaFunctions **functions) } #endif -static inline int cuvid_load_functions(CuvidFunctions **functions) +static inline int cuvid_load_functions(CuvidFunctions **functions, void *logctx) { GENERIC_LOAD_FUNC_PREAMBLE(CuvidFunctions, cuvid, NVCUVID_LIBNAME); @@ -244,7 +244,7 @@ static inline int cuvid_load_functions(CuvidFunctions **functions) GENERIC_LOAD_FUNC_FINALE(cuvid); } -static inline int nvenc_load_functions(NvencFunctions **functions) +static inline int nvenc_load_functions(NvencFunctions **functions, void *logctx) { GENERIC_LOAD_FUNC_PREAMBLE(NvencFunctions, nvenc, NVENC_LIBNAME); diff --git a/compat/nvenc/nvEncodeAPI.h b/compat/nvenc/nvEncodeAPI.h index c3a829421..e662880f4 100644 --- a/compat/nvenc/nvEncodeAPI.h +++ b/compat/nvenc/nvEncodeAPI.h @@ -77,7 +77,7 @@ extern "C" { typedef RECT NVENC_RECT; #else // ========================================================================================= -#ifndef GUID +#if !defined(GUID) && !defined(GUID_DEFINED) /*! * \struct GUID * Abstracts the GUID structure for non-windows platforms. diff --git a/compat/os2threads.h b/compat/os2threads.h index 40a119ffe..2177a033e 100644 --- a/compat/os2threads.h +++ b/compat/os2threads.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 KO Myung-Hun + * Copyright (c) 2011-2017 KO Myung-Hun * * This file is part of FFmpeg. * @@ -46,9 +46,11 @@ typedef struct { typedef void pthread_attr_t; -typedef HMTX pthread_mutex_t; +typedef _fmutex pthread_mutex_t; typedef void pthread_mutexattr_t; +#define PTHREAD_MUTEX_INITIALIZER _FMUTEX_INITIALIZER + typedef struct { HEV event_sem; HEV ack_sem; @@ -98,28 +100,28 @@ static av_always_inline int pthread_join(pthread_t thread, void **value_ptr) static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { - DosCreateMutexSem(NULL, (PHMTX)mutex, 0, FALSE); + _fmutex_create(mutex, 0); return 0; } static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex) { - DosCloseMutexSem(*(PHMTX)mutex); + _fmutex_close(mutex); return 0; } static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex) { - DosRequestMutexSem(*(PHMTX)mutex, SEM_INDEFINITE_WAIT); + _fmutex_request(mutex, 0); return 0; } static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex) { - DosReleaseMutexSem(*(PHMTX)mutex); + _fmutex_release(mutex); return 0; } diff --git a/compat/w32dlfcn.h b/compat/w32dlfcn.h index 78cc8f4c9..c83bdc933 100644 --- a/compat/w32dlfcn.h +++ b/compat/w32dlfcn.h @@ -21,6 +21,7 @@ #ifdef _WIN32 #include +#include "config.h" #if (_WIN32_WINNT < 0x0602) || HAVE_WINRT #include "libavutil/wchar_filename.h" #endif diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h index eeead6051..21acfd2ba 100644 --- a/compat/w32pthreads.h +++ b/compat/w32pthreads.h @@ -39,11 +39,6 @@ #include #include -#if _WIN32_WINNT < 0x0600 && defined(__MINGW32__) -#undef MemoryBarrier -#define MemoryBarrier __sync_synchronize -#endif - #include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/internal.h" @@ -56,24 +51,15 @@ typedef struct pthread_t { void *ret; } pthread_t; -/* the conditional variable api for windows 6.0+ uses critical sections and - * not mutexes */ -typedef CRITICAL_SECTION pthread_mutex_t; - -/* This is the CONDITION_VARIABLE typedef for using Windows' native - * conditional variables on kernels 6.0+. */ -#if HAVE_CONDITION_VARIABLE_PTR +/* use light weight mutex/condition variable API for Windows Vista and later */ +typedef SRWLOCK pthread_mutex_t; typedef CONDITION_VARIABLE pthread_cond_t; -#else -typedef struct pthread_cond_t { - void *Ptr; -} pthread_cond_t; -#endif -#if _WIN32_WINNT >= 0x0600 +#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT +#define PTHREAD_COND_INITIALIZER CONDITION_VARIABLE_INIT + #define InitializeCriticalSection(x) InitializeCriticalSectionEx(x, 0, 0) #define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE) -#endif static av_unused unsigned __stdcall attribute_align_arg win32thread_worker(void *arg) { @@ -114,26 +100,25 @@ static av_unused int pthread_join(pthread_t thread, void **value_ptr) static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr) { - InitializeCriticalSection(m); + InitializeSRWLock(m); return 0; } static inline int pthread_mutex_destroy(pthread_mutex_t *m) { - DeleteCriticalSection(m); + /* Unlocked SWR locks use no resources */ return 0; } static inline int pthread_mutex_lock(pthread_mutex_t *m) { - EnterCriticalSection(m); + AcquireSRWLockExclusive(m); return 0; } static inline int pthread_mutex_unlock(pthread_mutex_t *m) { - LeaveCriticalSection(m); + ReleaseSRWLockExclusive(m); return 0; } -#if _WIN32_WINNT >= 0x0600 typedef INIT_ONCE pthread_once_t; #define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT @@ -167,7 +152,7 @@ static inline int pthread_cond_broadcast(pthread_cond_t *cond) static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - SleepConditionVariableCS(cond, mutex, INFINITE); + SleepConditionVariableSRW(cond, mutex, INFINITE, 0); return 0; } @@ -177,242 +162,4 @@ static inline int pthread_cond_signal(pthread_cond_t *cond) return 0; } -#else // _WIN32_WINNT < 0x0600 - -/* atomic init state of dynamically loaded functions */ -static LONG w32thread_init_state = 0; -static av_unused void w32thread_init(void); - -/* for pre-Windows 6.0 platforms, define INIT_ONCE struct, - * compatible to the one used in the native API */ - -typedef union pthread_once_t { - void * Ptr; ///< For the Windows 6.0+ native functions - LONG state; ///< For the pre-Windows 6.0 compat code -} pthread_once_t; - -#define PTHREAD_ONCE_INIT {0} - -/* function pointers to init once API on windows 6.0+ kernels */ -static BOOL (WINAPI *initonce_begin)(pthread_once_t *lpInitOnce, DWORD dwFlags, BOOL *fPending, void **lpContext); -static BOOL (WINAPI *initonce_complete)(pthread_once_t *lpInitOnce, DWORD dwFlags, void *lpContext); - -/* pre-Windows 6.0 compat using a spin-lock */ -static inline void w32thread_once_fallback(LONG volatile *state, void (*init_routine)(void)) -{ - switch (InterlockedCompareExchange(state, 1, 0)) { - /* Initial run */ - case 0: - init_routine(); - InterlockedExchange(state, 2); - break; - /* Another thread is running init */ - case 1: - while (1) { - MemoryBarrier(); - if (*state == 2) - break; - Sleep(0); - } - break; - /* Initialization complete */ - case 2: - break; - } -} - -static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) -{ - w32thread_once_fallback(&w32thread_init_state, w32thread_init); - - /* Use native functions on Windows 6.0+ */ - if (initonce_begin && initonce_complete) { - BOOL pending = FALSE; - initonce_begin(once_control, 0, &pending, NULL); - if (pending) - init_routine(); - initonce_complete(once_control, 0, NULL); - return 0; - } - - w32thread_once_fallback(&once_control->state, init_routine); - return 0; -} - -/* for pre-Windows 6.0 platforms we need to define and use our own condition - * variable and api */ - -typedef struct win32_cond_t { - pthread_mutex_t mtx_broadcast; - pthread_mutex_t mtx_waiter_count; - volatile int waiter_count; - HANDLE semaphore; - HANDLE waiters_done; - volatile int is_broadcast; -} win32_cond_t; - -/* function pointers to conditional variable API on windows 6.0+ kernels */ -static void (WINAPI *cond_broadcast)(pthread_cond_t *cond); -static void (WINAPI *cond_init)(pthread_cond_t *cond); -static void (WINAPI *cond_signal)(pthread_cond_t *cond); -static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex, - DWORD milliseconds); - -static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr) -{ - win32_cond_t *win32_cond = NULL; - - w32thread_once_fallback(&w32thread_init_state, w32thread_init); - - if (cond_init) { - cond_init(cond); - return 0; - } - - /* non native condition variables */ - win32_cond = (win32_cond_t*)av_mallocz(sizeof(win32_cond_t)); - if (!win32_cond) - return ENOMEM; - cond->Ptr = win32_cond; - win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - if (!win32_cond->semaphore) - return ENOMEM; - win32_cond->waiters_done = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!win32_cond->waiters_done) - return ENOMEM; - - pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL); - pthread_mutex_init(&win32_cond->mtx_broadcast, NULL); - return 0; -} - -static av_unused int pthread_cond_destroy(pthread_cond_t *cond) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - /* native condition variables do not destroy */ - if (cond_init) - return 0; - - /* non native condition variables */ - CloseHandle(win32_cond->semaphore); - CloseHandle(win32_cond->waiters_done); - pthread_mutex_destroy(&win32_cond->mtx_waiter_count); - pthread_mutex_destroy(&win32_cond->mtx_broadcast); - av_freep(&win32_cond); - cond->Ptr = NULL; - return 0; -} - -static av_unused int pthread_cond_broadcast(pthread_cond_t *cond) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - int have_waiter; - - if (cond_broadcast) { - cond_broadcast(cond); - return 0; - } - - /* non native condition variables */ - pthread_mutex_lock(&win32_cond->mtx_broadcast); - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - have_waiter = 0; - - if (win32_cond->waiter_count) { - win32_cond->is_broadcast = 1; - have_waiter = 1; - } - - if (have_waiter) { - ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL); - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - WaitForSingleObject(win32_cond->waiters_done, INFINITE); - ResetEvent(win32_cond->waiters_done); - win32_cond->is_broadcast = 0; - } else - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - pthread_mutex_unlock(&win32_cond->mtx_broadcast); - return 0; -} - -static av_unused int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - int last_waiter; - if (cond_wait) { - cond_wait(cond, mutex, INFINITE); - return 0; - } - - /* non native condition variables */ - pthread_mutex_lock(&win32_cond->mtx_broadcast); - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - win32_cond->waiter_count++; - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - pthread_mutex_unlock(&win32_cond->mtx_broadcast); - - // unlock the external mutex - pthread_mutex_unlock(mutex); - WaitForSingleObject(win32_cond->semaphore, INFINITE); - - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - win32_cond->waiter_count--; - last_waiter = !win32_cond->waiter_count || !win32_cond->is_broadcast; - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - - if (last_waiter) - SetEvent(win32_cond->waiters_done); - - // lock the external mutex - return pthread_mutex_lock(mutex); -} - -static av_unused int pthread_cond_signal(pthread_cond_t *cond) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - int have_waiter; - if (cond_signal) { - cond_signal(cond); - return 0; - } - - pthread_mutex_lock(&win32_cond->mtx_broadcast); - - /* non-native condition variables */ - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - have_waiter = win32_cond->waiter_count; - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - - if (have_waiter) { - ReleaseSemaphore(win32_cond->semaphore, 1, NULL); - WaitForSingleObject(win32_cond->waiters_done, INFINITE); - ResetEvent(win32_cond->waiters_done); - } - - pthread_mutex_unlock(&win32_cond->mtx_broadcast); - return 0; -} -#endif - -static av_unused void w32thread_init(void) -{ -#if _WIN32_WINNT < 0x0600 - HMODULE kernel_dll = GetModuleHandle(TEXT("kernel32.dll")); - /* if one is available, then they should all be available */ - cond_init = (void (WINAPI*)(pthread_cond_t *)) - GetProcAddress(kernel_dll, "InitializeConditionVariable"); - cond_broadcast = (void (WINAPI*)(pthread_cond_t *)) - GetProcAddress(kernel_dll, "WakeAllConditionVariable"); - cond_signal = (void (WINAPI*)(pthread_cond_t *)) - GetProcAddress(kernel_dll, "WakeConditionVariable"); - cond_wait = (BOOL (WINAPI*)(pthread_cond_t *, pthread_mutex_t *, DWORD)) - GetProcAddress(kernel_dll, "SleepConditionVariableCS"); - initonce_begin = (BOOL (WINAPI*)(pthread_once_t *, DWORD, BOOL *, void **)) - GetProcAddress(kernel_dll, "InitOnceBeginInitialize"); - initonce_complete = (BOOL (WINAPI*)(pthread_once_t *, DWORD, void *)) - GetProcAddress(kernel_dll, "InitOnceComplete"); -#endif - -} - #endif /* COMPAT_W32PTHREADS_H */ diff --git a/compat/windows/makedef b/compat/windows/makedef index fcaf10833..7258b94a9 100755 --- a/compat/windows/makedef +++ b/compat/windows/makedef @@ -45,7 +45,11 @@ libname=$(mktemp -u "library").lib trap 'rm -f -- $libname' EXIT -lib -out:${libname} $@ >/dev/null +if [ -n "$AR" ]; then + $AR rcs ${libname} $@ >/dev/null +else + lib -out:${libname} $@ >/dev/null +fi if [ $? != 0 ]; then echo "Could not create temporary library." >&2 exit 1 @@ -54,23 +58,7 @@ fi IFS=' ' -# Determine if we're building for x86 or x86_64 and -# set the symbol prefix accordingly. -prefix="" -arch=$(dumpbin -headers ${libname} | - tr '\t' ' ' | - grep '^ \+.\+machine \+(.\+)' | - head -1 | - sed -e 's/^ \{1,\}.\{1,\} \{1,\}machine \{1,\}(\(...\)).*/\1/') - -if [ "${arch}" = "x86" ]; then - prefix="_" -else - if [ "${arch}" != "ARM" ] && [ "${arch}" != "x64" ]; then - echo "Unknown machine type." >&2 - exit 1 - fi -fi +prefix="$EXTERN_PREFIX" started=0 regex="none" @@ -112,7 +100,19 @@ for line in $(cat ${vscript} | tr '\t' ' '); do ' done -dump=$(dumpbin -linkermember:1 ${libname}) +if [ -n "$NM" ]; then + # Use eval, since NM="nm -g" + dump=$(eval "$NM --defined-only -g ${libname}" | + grep -v : | + grep -v ^$ | + cut -d' ' -f3 | + sed -e "s/^${prefix}//") +else + dump=$(dumpbin -linkermember:1 ${libname} | + sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' | + tail -n +2 | + cut -d' ' -f3) +fi rm ${libname} @@ -121,9 +121,6 @@ list="" for exp in ${regex}; do list="${list}"' '$(echo "${dump}" | - sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' | - tail -n +2 | - cut -d' ' -f3 | grep "^${exp}" | sed -e 's/^/ /') done diff --git a/configure b/configure index 18d80ee87..5d533621a 100755 --- a/configure +++ b/configure @@ -116,7 +116,6 @@ Program options: --disable-ffmpeg disable ffmpeg build --disable-ffplay disable ffplay build --disable-ffprobe disable ffprobe build - --disable-ffserver disable ffserver build Documentation options: --disable-doc do not build documentation @@ -133,7 +132,7 @@ Component options: --disable-swscale disable libswscale build --disable-postproc disable libpostproc build --disable-avfilter disable libavfilter build - --enable-avresample enable libavresample build [no] + --enable-avresample enable libavresample build (deprecated) [no] --disable-pthreads disable pthreads [autodetect] --disable-w32threads disable Win32 threads [autodetect] --disable-os2threads disable OS/2 threads [autodetect] @@ -185,7 +184,6 @@ Individual component options: --enable-filter=NAME enable filter NAME --disable-filter=NAME disable filter NAME --disable-filters disable all filters - --disable-v4l2_m2m disable V4L2 mem2mem code [autodetect] External library support: @@ -215,9 +213,8 @@ External library support: --enable-gmp enable gmp, needed for rtmp(t)e support if openssl or librtmp is not used [no] --enable-gnutls enable gnutls, needed for https support - if openssl is not used [no] + if openssl or libtls is not used [no] --disable-iconv disable iconv [autodetect] - --disable-jack disable libjack support [autodetect] --enable-jni enable JNI support [no] --enable-ladspa enable LADSPA audio filtering [no] --enable-libass enable libass subtitles rendering, @@ -238,6 +235,7 @@ External library support: --enable-libgsm enable GSM de/encoding via libgsm [no] --enable-libiec61883 enable iec61883 via libiec61883 [no] --enable-libilbc enable iLBC de/encoding via libilbc [no] + --enable-libjack enable JACK audio sound server [no] --enable-libkvazaar enable HEVC encoding via libkvazaar [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] @@ -260,6 +258,8 @@ External library support: --enable-libssh enable SFTP protocol via libssh [no] --enable-libtesseract enable Tesseract, needed for ocr filter [no] --enable-libtheora enable Theora encoding via libtheora [no] + --enable-libtls enable LibreSSL (via libtls), needed for https support + if openssl or gnutls is not used [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libv4l2 enable libv4l2/v4l-utils [no] --enable-libvidstab enable video stabilization using vid.stab [no] @@ -283,16 +283,17 @@ External library support: --enable-libzimg enable z.lib, needed for zscale filter [no] --enable-libzmq enable message passing via libzmq [no] --enable-libzvbi enable teletext support via libzvbi [no] + --enable-lv2 enable LV2 audio filtering [no] --disable-lzma disable lzma [autodetect] --enable-decklink enable Blackmagic DeckLink I/O support [no] --enable-libndi_newtek enable Newteck NDI I/O support [no] --enable-mediacodec enable Android MediaCodec support [no] --enable-libmysofa enable libmysofa, needed for sofalizer filter [no] --enable-openal enable OpenAL 1.1 capture support [no] - --enable-opencl enable OpenCL code + --enable-opencl enable OpenCL processing [no] --enable-opengl enable OpenGL rendering [no] --enable-openssl enable openssl, needed for https support - if gnutls is not used [no] + if gnutls or libtls is not used [no] --disable-sndio disable sndio support [autodetect] --disable-schannel disable SChannel SSP, needed for TLS support on Windows if openssl and gnutls are not used [autodetect] @@ -303,6 +304,7 @@ External library support: --disable-zlib disable zlib [autodetect] The following libraries provide various hardware acceleration features: + --disable-amf disable AMF video encoding code [autodetect] --disable-audiotoolbox disable Apple AudioToolbox code [autodetect] --disable-cuda disable dynamically linked Nvidia CUDA code [autodetect] --enable-cuda-sdk enable CUDA features that require the CUDA SDK [no] @@ -313,12 +315,13 @@ External library support: --enable-libmfx enable Intel MediaSDK (AKA Quick Sync Video) code via libmfx [no] --enable-libnpp enable Nvidia Performance Primitives-based code [no] --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no] + --disable-nvdec disable Nvidia video decoding acceleration (via hwaccel) [autodetect] --disable-nvenc disable Nvidia video encoding code [autodetect] --enable-omx enable OpenMAX IL code [no] --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no] --enable-rkmpp enable Rockchip Media Process Platform code [no] + --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect] --disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect] - --disable-vda disable Apple Video Decode Acceleration code [autodetect] --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] --disable-videotoolbox disable VideoToolbox code [autodetect] @@ -366,7 +369,7 @@ Toolchain options: --extra-objcflags=FLAGS add FLAGS to OBJCFLAGS [$CFLAGS] --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS] --extra-ldexeflags=ELDFLAGS add ELDFLAGS to LDEXEFLAGS [$LDEXEFLAGS] - --extra-ldlibflags=ELDFLAGS add ELDFLAGS to LDLIBFLAGS [$LDLIBFLAGS] + --extra-ldsoflags=ELDFLAGS add ELDFLAGS to LDSOFLAGS [$LDSOFLAGS] --extra-libs=ELIBS add ELIBS [$ELIBS] --extra-version=STRING version string suffix [] --optflags=OPTFLAGS override optimization-related compiler flags @@ -407,6 +410,7 @@ Optimization options (experts only): --disable-fma3 disable FMA3 optimizations --disable-fma4 disable FMA4 optimizations --disable-avx2 disable AVX2 optimizations + --disable-avx512 disable AVX-512 optimizations --disable-aesni disable AESNI optimizations --disable-armv5te disable armv5te optimizations --disable-armv6 disable armv6 optimizations @@ -462,7 +466,6 @@ EOF exit 0 } -quotes='""' if test -t 1 && which tput >/dev/null 2>&1; then ncolors=$(tput colors) if test -n "$ncolors" && test $ncolors -ge 8; then @@ -541,7 +544,7 @@ filter(){ pat=$1 shift for v; do - eval "case $v in $pat) printf '%s ' $v ;; esac" + eval "case '$v' in $pat) printf '%s ' '$v' ;; esac" done } @@ -549,7 +552,7 @@ filter_out(){ pat=$1 shift for v; do - eval "case $v in $pat) ;; *) printf '%s ' $v ;; esac" + eval "case '$v' in $pat) ;; *) printf '%s ' '$v' ;; esac" done } @@ -585,13 +588,13 @@ sanitize_var_name(){ echo $@ | sed 's/[^A-Za-z0-9_]/_/g' } -set_safe(){ +set_sanitized(){ var=$1 shift eval $(sanitize_var_name "$var")='$*' } -get_safe(){ +get_sanitized(){ eval echo \$$(sanitize_var_name "$1") } @@ -637,15 +640,15 @@ disable_weak(){ set_weak no $* } -enable_safe(){ +enable_sanitized(){ for var; do - enable $(echo "$var" | sed 's/[^A-Za-z0-9_]/_/g') + enable $(sanitize_var_name $var) done } -disable_safe(){ +disable_sanitized(){ for var; do - disable $(echo "$var" | sed 's/[^A-Za-z0-9_]/_/g') + disable $(sanitize_var_name $var) done } @@ -678,17 +681,17 @@ enable_deep_weak(){ } requested(){ - test "${1#!}" = "$1" && op='=' || op=!= + test "${1#!}" = "$1" && op="=" || op="!=" eval test "x\$${1#!}_requested" $op "xyes" } enabled(){ - test "${1#!}" = "$1" && op='=' || op=!= + test "${1#!}" = "$1" && op="=" || op="!=" eval test "x\$${1#!}" $op "xyes" } disabled(){ - test "${1#!}" = "$1" && op='=' || op=!= + test "${1#!}" = "$1" && op="=" || op="!=" eval test "x\$${1#!}" $op "xno" } @@ -732,12 +735,11 @@ is_in(){ return 1 } -do_check_deps(){ +check_deps(){ for cfg; do enabled ${cfg}_checking && die "Circular dependency for $cfg." disabled ${cfg}_checking && continue enable ${cfg}_checking - append allopts $cfg eval dep_all="\$${cfg}_deps" eval dep_any="\$${cfg}_deps_any" @@ -748,7 +750,7 @@ do_check_deps(){ eval dep_ifn="\$${cfg}_if_any" pushvar cfg dep_all dep_any dep_con dep_sel dep_sgs dep_ifa dep_ifn - do_check_deps $dep_all $dep_any $dep_con $dep_sel $dep_sgs $dep_ifa $dep_ifn + check_deps $dep_all $dep_any $dep_con $dep_sel $dep_sgs $dep_ifa $dep_ifn popvar cfg dep_all dep_any dep_con dep_sel dep_sgs dep_ifa dep_ifn [ -n "$dep_ifa" ] && { enabled_all $dep_ifa && enable_weak $cfg; } @@ -758,27 +760,18 @@ do_check_deps(){ disabled_all $dep_con || { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but some conflicting dependencies are unsatisfied: $dep_con"; } disabled_any $dep_sel && { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but some selected dependency is unsatisfied: $dep_sel"; } - if enabled $cfg; then - enable_deep $dep_sel - enable_deep_weak $dep_sgs - fi + enabled $cfg && enable_deep_weak $dep_sel $dep_sgs + + for dep in $dep_all $dep_any $dep_sel $dep_sgs; do + # filter out library deps, these do not belong in extralibs + is_in $dep $LIBRARY_LIST && continue + enabled $dep && eval append ${cfg}_extralibs ${dep}_extralibs + done disable ${cfg}_checking done } -check_deps(){ - unset allopts - - do_check_deps "$@" - - for cfg in $allopts; do - enabled $cfg || continue - eval dep_extralibs="\$${cfg}_extralibs" - test -n "$dep_extralibs" && add_extralibs $dep_extralibs - done -} - print_config(){ pfx=$1 files=$2 @@ -839,6 +832,15 @@ unique(){ eval "$var=\"${uniq_list}\"" } +resolve(){ + var=$1 + tmpvar= + for entry in $(eval echo \$$var); do + tmpvar="$tmpvar $(eval echo \$${entry})" + done + eval "$var=\"${tmpvar}\"" +} + add_cppflags(){ append CPPFLAGS "$@" } @@ -871,8 +873,8 @@ add_ldexeflags(){ append LDEXEFLAGS $($ldflags_filter "$@") } -add_ldlibflags(){ - append LDLIBFLAGS $($ldflags_filter "$@") +add_ldsoflags(){ + append LDSOFLAGS $($ldflags_filter "$@") } add_stripflags(){ @@ -1082,6 +1084,7 @@ check_objcflags(){ test_ldflags(){ log test_ldflags "$@" + set -- $($ldflags_filter "$@") check_ld "cc" "$@" < -int x; -EOF + disable_sanitized $headers + { + for hdr in $headers; do + print_include $hdr + done + echo "int x;" + } | check_cpp "$@" && enable_sanitized $headers } check_header_objcc(){ @@ -1122,11 +1127,11 @@ check_header_objcc(){ rm -f -- "$TMPO" header=$1 shift - disable_safe $header + disable_sanitized $header { echo "#include <$header>" echo "int main(void) { return 0; }" - } | check_objcc && check_stat "$TMPO" && enable_safe $header + } | check_objcc && check_stat "$TMPO" && enable_sanitized $header } check_apple_framework(){ @@ -1135,7 +1140,8 @@ check_apple_framework(){ name="$(tolower $framework)" header="${framework}/${framework}.h" disable $name - check_header_objcc $header && enable $name && add_extralibs "-framework $framework" + check_header_objcc $header && + enable $name && eval ${name}_extralibs='"-framework $framework"' } check_func(){ @@ -1197,7 +1203,7 @@ check_func_headers(){ echo " ret |= ((intptr_t)check_$func) & 0xFFFF;" done echo "return ret; }" - } | check_ld "cc" "$@" && enable $funcs && enable_safe $headers + } | check_ld "cc" "$@" && enable $funcs && enable_sanitized $headers } check_class_headers_cpp(){ @@ -1216,7 +1222,7 @@ check_class_headers_cpp(){ i=$(expr $i + 1) done echo "return 0; }" - } | check_ld "cxx" "$@" && enable $funcs && enable_safe $headers + } | check_ld "cxx" "$@" && enable $funcs && enable_sanitized $headers } check_cpp_condition(){ @@ -1255,19 +1261,22 @@ check_lib(){ shift 3 disable $name check_func_headers "$headers" "$funcs" "$@" && - enable $name && add_extralibs "$@" + enable $name && eval ${name}_extralibs="\$@" } check_lib_cpp(){ log check_lib_cpp "$@" - headers="$1" - classes="$2" - shift 2 - check_class_headers_cpp "$headers" "$classes" "$@" && add_extralibs "$@" + name="$1" + headers="$2" + classes="$3" + shift 3 + disable $name + check_class_headers_cpp "$headers" "$classes" "$@" && + enable $name && eval ${name}_extralibs="\$@" } -check_pkg_config(){ - log check_pkg_config "$@" +test_pkg_config(){ + log test_pkg_config "$@" name="$1" pkg_version="$2" pkg="${2%% *}" @@ -1280,8 +1289,15 @@ check_pkg_config(){ pkg_libs=$($pkg_config --libs $pkg_config_flags $pkg) check_func_headers "$headers" "$funcs" $pkg_cflags $pkg_libs "$@" && enable $name && - set_safe "${pkg}_cflags" $pkg_cflags && - set_safe "${pkg}_extralibs" $pkg_libs + 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 } check_exec(){ @@ -1324,8 +1340,8 @@ check_type(){ headers=$1 type=$2 shift 2 - disable_safe "$type" - check_code cc "$headers" "$type v" "$@" && enable_safe "$type" + disable_sanitized "$type" + check_code cc "$headers" "$type v" "$@" && enable_sanitized "$type" } check_struct(){ @@ -1334,9 +1350,9 @@ check_struct(){ struct=$2 member=$3 shift 3 - disable_safe "${struct}_${member}" + disable_sanitized "${struct}_${member}" check_code cc "$headers" "const void *p = &(($struct *)0)->$member" "$@" && - enable_safe "${struct}_${member}" + enable_sanitized "${struct}_${member}" } check_builtin(){ @@ -1378,32 +1394,24 @@ require_cpp(){ } require_header(){ - log require "$@" - header="$1" + log require_header "$@" + headers="$1" shift - check_header "$header" "$@" || die "ERROR: $header header not found" + check_header "$headers" "$@" || die "ERROR: $headers not found" } require_cpp_condition(){ - log require "$@" + log require_cpp_condition "$@" header="$1" condition="$2" shift 2 check_cpp_condition "$header" "$condition" "$@" || die "ERROR: $condition not satisfied" } -use_pkg_config(){ - log use_pkg_config "$@" - pkg="${2%% *}" - check_pkg_config "$@" || return 1 - add_cflags $(get_safe "${pkg}_cflags") - add_extralibs $(get_safe "${pkg}_extralibs") -} - require_pkg_config(){ log require_pkg_config "$@" pkg_version="$2" - use_pkg_config "$@" || die "ERROR: $pkg_version not found using pkg-config$pkg_config_fail_message" + check_pkg_config "$@" || die "ERROR: $pkg_version not found using pkg-config$pkg_config_fail_message" } hostcc_e(){ @@ -1488,17 +1496,11 @@ AVFORMAT_COMPONENTS=" protocols " -AVRESAMPLE_COMPONENTS="" - -AVUTIL_COMPONENTS="" - COMPONENT_LIST=" $AVCODEC_COMPONENTS $AVDEVICE_COMPONENTS $AVFILTER_COMPONENTS $AVFORMAT_COMPONENTS - $AVRESAMPLE_COMPONENTS - $AVUTIL_COMPONENTS " EXAMPLE_LIST=" @@ -1523,6 +1525,7 @@ EXAMPLE_LIST=" scaling_video_example transcode_aac_example transcoding_example + vaapi_encode_example " EXTERNAL_AUTODETECT_LIBRARY_LIST=" @@ -1532,7 +1535,6 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" bzlib coreimage iconv - jack libxcb libxcb_shm libxcb_shape @@ -1563,12 +1565,14 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" libndi_newtek libfdk_aac openssl + libtls " EXTERNAL_LIBRARY_VERSION3_LIST=" gmp libopencore_amrnb libopencore_amrwb + libvmaf libvo_amrwbenc rkmpp " @@ -1578,7 +1582,6 @@ EXTERNAL_LIBRARY_GPLV3_LIST=" " EXTERNAL_LIBRARY_LIST=" - $EXTERNAL_AUTODETECT_LIBRARY_LIST $EXTERNAL_LIBRARY_GPL_LIST $EXTERNAL_LIBRARY_NONFREE_LIST $EXTERNAL_LIBRARY_VERSION3_LIST @@ -1603,6 +1606,7 @@ EXTERNAL_LIBRARY_LIST=" libgsm libiec61883 libilbc + libjack libkvazaar libmodplug libmp3lame @@ -1625,7 +1629,6 @@ EXTERNAL_LIBRARY_LIST=" libtheora libtwolame libv4l2 - libvmaf libvorbis libvpx libwavpack @@ -1634,39 +1637,46 @@ EXTERNAL_LIBRARY_LIST=" libzimg libzmq libzvbi + lv2 mediacodec openal - opencl opengl " HWACCEL_AUTODETECT_LIBRARY_LIST=" + amf audiotoolbox crystalhd cuda cuvid d3d11va dxva2 + nvdec nvenc vaapi - vda 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_sdk libnpp " HWACCEL_LIBRARY_LIST=" - $HWACCEL_AUTODETECT_LIBRARY_LIST $HWACCEL_LIBRARY_NONFREE_LIST libmfx mmal omx + opencl " DOCUMENT_LIST=" @@ -1711,7 +1721,6 @@ LICENSE_LIST=" PROGRAM_LIST=" ffplay ffprobe - ffserver ffmpeg " @@ -1735,7 +1744,9 @@ 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 @@ -1834,6 +1845,7 @@ ARCH_EXT_LIST_X86_SIMD=" amd3dnowext avx avx2 + avx512 fma3 fma4 mmx @@ -1875,11 +1887,10 @@ ARCH_FEATURES=" fast_64bit fast_clz fast_cmov - local_aligned_8 - local_aligned_16 - local_aligned_32 + local_aligned simd_align_16 simd_align_32 + simd_align_64 " BUILTIN_LIST=" @@ -1888,7 +1899,6 @@ BUILTIN_LIST=" MemoryBarrier mm_empty rdtsc - sarestart sem_timedwait sync_val_compare_and_swap " @@ -1904,13 +1914,11 @@ HAVE_LIST_PUB=" " HEADERS_LIST=" - altivec_h arpa_inet_h asm_types_h cdio_paranoia_h cdio_paranoia_paranoia_h cuda_h - d3d11_h dispatch_dispatch_h dev_bktr_ioctl_bt848_h dev_bktr_ioctl_meteor_h @@ -1919,27 +1927,17 @@ HEADERS_LIST=" dev_video_meteor_ioctl_meteor_h direct_h dirent_h - dlfcn_h dxgidebug_h dxva_h ES2_gl_h gsm_h io_h - mach_mach_time_h machine_ioctl_bt848_h machine_ioctl_meteor_h malloc_h opencv2_core_core_c_h - openjpeg_2_3_openjpeg_h - openjpeg_2_2_openjpeg_h - openjpeg_2_1_openjpeg_h - openjpeg_2_0_openjpeg_h - openjpeg_1_5_openjpeg_h OpenGL_gl3_h poll_h - soundcard_h - stdatomic_h - sys_mman_h sys_param_h sys_resource_h sys_select_h @@ -1996,6 +1994,16 @@ MATH_FUNCS=" 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 @@ -2003,11 +2011,7 @@ SYSTEM_FUNCS=" clock_gettime closesocket CommandLineToArgvW - CoTaskMemFree - CryptGenRandom fcntl - flt_lim - fork getaddrinfo gethrtime getopt @@ -2022,9 +2026,7 @@ SYSTEM_FUNCS=" gmtime_r inet_aton isatty - jack_port_get_latency_range kbhit - LoadLibrary localtime_r lstat lzo1x_999_compress @@ -2039,6 +2041,7 @@ SYSTEM_FUNCS=" posix_memalign pthread_cancel sched_getaffinity + SecItemImport SetConsoleTextAttribute SetConsoleCtrlHandler setmode @@ -2053,14 +2056,19 @@ SYSTEM_FUNCS=" wglGetProcAddress " +SYSTEM_LIBRARIES=" + vaapi_drm + vaapi_x11 + vdpau_x11 + wincrypt +" + TOOLCHAIN_FEATURES=" - as_dn_directive + as_arch_directive as_fpu_directive as_func as_object_arch asm_mod_q - attribute_may_alias - attribute_packed blocks_extension ebp_available ebx_available @@ -2080,7 +2088,6 @@ TOOLCHAIN_FEATURES=" " TYPES_LIST=" - CONDITION_VARIABLE_Ptr kCMVideoCodecType_HEVC socklen_t struct_addrinfo @@ -2103,7 +2110,6 @@ HAVE_LIST=" $(add_suffix _external $ARCH_EXT_LIST) $(add_suffix _inline $ARCH_EXT_LIST) $ARCH_FEATURES - $ATOMICS_LIST $BUILTIN_LIST $COMPLEX_FUNCS $HAVE_LIST_CMDLINE @@ -2111,37 +2117,38 @@ HAVE_LIST=" $HEADERS_LIST $INTRINSICS_LIST $MATH_FUNCS + $SYSTEM_FEATURES $SYSTEM_FUNCS + $SYSTEM_LIBRARIES $THREADS_LIST $TOOLCHAIN_FEATURES $TYPES_LIST - atomics_native - dos_paths - libc_msvcrt makeinfo makeinfo_html - MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS + opencl_d3d11 + opencl_drm_arm + opencl_dxva2 + opencl_vaapi_beignet + opencl_vaapi_intel_media perl pod2man - section_data_rel_ro texi2html - threads - uwp - vaapi_drm - vaapi_x11 - vdpau_x11 - winrt " # 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_h264 + cbs_h265 + cbs_mpeg2 dirac_parse dvprofile exif @@ -2192,6 +2199,7 @@ CONFIG_EXTRA=" qsv qsvdec qsvenc + qsvvpp rangecoder riffdec riffenc @@ -2321,19 +2329,6 @@ setend_deps="arm" map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM -loongson2_deps="mips" -loongson3_deps="mips" -mipsfpu_deps="mips" -mipsdsp_deps="mips" -mipsdspr2_deps="mips" -mips32r2_deps="mips" -mips32r5_deps="mips" -mips32r6_deps="mips" -mips64r2_deps="mips" -mips64r6_deps="mips" -msa_deps="mipsfpu" -mmi_deps="mips" - altivec_deps="ppc" dcbzl_deps="ppc" ldbrx_deps="ppc" @@ -2341,6 +2336,19 @@ 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" + cpunop_deps="i686" x86_64_select="i686" x86_64_suggest="fast_cmov" @@ -2362,9 +2370,10 @@ xop_deps="avx" fma3_deps="avx" fma4_deps="avx" avx2_deps="avx" +avx512_deps="avx2" mmx_external_deps="x86asm" -mmx_inline_deps="inline_asm" +mmx_inline_deps="inline_asm x86" mmx_suggest="mmx_external mmx_inline" for ext in $(filter_out mmx $ARCH_EXT_LIST_X86_SIMD); do @@ -2380,6 +2389,7 @@ 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 symver_if_any="symver_asm_label symver_gnu_asm" @@ -2395,11 +2405,16 @@ w32threads_deps="atomics_native" threads_if_any="$THREADS_LIST" # subsystems +cbs_h264_select="cbs golomb" +cbs_h265_select="cbs golomb" +cbs_mpeg2_select="cbs" dct_select="rdft" dirac_parse_select="golomb" error_resilience_select="me_cmp" -faandct_deps="faan fdctdsp" -faanidct_deps="faan idctdsp" +faandct_deps="faan" +faandct_select="fdctdsp" +faanidct_deps="faan" +faanidct_select="idctdsp" h264dsp_select="startcode" hevcparse_select="golomb" frame_thread_encoder_deps="encoders threads" @@ -2416,7 +2431,7 @@ vc1dsp_select="h264chroma qpeldsp startcode" rdft_select="fft" # decoders / encoders -aac_decoder_select="mdct15 mdct sinewin" +aac_decoder_select="adts_header mdct15 mdct sinewin" aac_fixed_decoder_select="mdct sinewin" aac_encoder_select="audio_frame_queue iirfilter lpc mdct sinewin" aac_latm_decoder_select="aac_decoder aac_latm_parser" @@ -2434,8 +2449,11 @@ amrwb_decoder_select="lsp" amv_decoder_select="sp5x_decoder exif" amv_encoder_select="aandcttables jpegtables mpegvideoenc" ape_decoder_select="bswapdsp llauddsp" -apng_decoder_select="zlib" -apng_encoder_select="llvidencdsp zlib" +apng_decoder_deps="zlib" +apng_encoder_deps="zlib" +apng_encoder_select="llvidencdsp" +aptx_decoder_select="audio_frame_queue" +aptx_encoder_select="audio_frame_queue" asv1_decoder_select="blockdsp bswapdsp idctdsp" asv1_encoder_select="bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" @@ -2462,14 +2480,14 @@ dnxhd_encoder_select="aandcttables blockdsp fdctdsp idctdsp mpegvideoenc pixbloc dolby_e_decoder_select="mdct" dvvideo_decoder_select="dvprofile idctdsp" dvvideo_encoder_select="dvprofile fdctdsp me_cmp pixblockdsp" -dxa_decoder_select="zlib" +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_select="zlib" +exr_decoder_deps="zlib" ffv1_decoder_select="rangecoder" ffv1_encoder_select="rangecoder" ffvhuff_decoder_select="huffyuv_decoder" @@ -2477,15 +2495,16 @@ ffvhuff_encoder_select="huffyuv_encoder" fic_decoder_select="golomb" flac_decoder_select="flacdsp" flac_encoder_select="bswapdsp flacdsp lpc" -flashsv2_decoder_select="zlib" -flashsv2_encoder_select="zlib" -flashsv_decoder_select="zlib" -flashsv_encoder_select="zlib" +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_select="blockdsp idctdsp jpegtables zlib" +g2m_decoder_deps="zlib" +g2m_decoder_select="blockdsp idctdsp jpegtables" g729_decoder_select="audiodsp" h261_decoder_select="mpegvideo" h261_encoder_select="aandcttables mpegvideoenc" @@ -2513,6 +2532,7 @@ jv_decoder_select="blockdsp" lagarith_decoder_select="llviddsp" ljpeg_encoder_select="aandcttables idctdsp jpegtables mpegvideoenc" 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" @@ -2534,8 +2554,6 @@ mp3on4_decoder_select="mpegaudio" mp3on4float_decoder_select="mpegaudio" mpc7_decoder_select="bswapdsp mpegaudiodsp" mpc8_decoder_select="mpegaudiodsp" -mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h" -mpeg_xvmc_decoder_select="mpeg2video_decoder" mpegvideo_decoder_select="mpegvideo" mpeg1video_decoder_select="mpegvideo" mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp" @@ -2544,7 +2562,7 @@ mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp" mpeg4_decoder_select="h263_decoder mpeg4video_parser" mpeg4_encoder_select="h263_encoder" msa1_decoder_select="mss34dsp" -mscc_decoder_select="zlib" +mscc_decoder_deps="zlib" msmpeg4v1_decoder_select="h263_decoder" msmpeg4v2_decoder_select="h263_decoder" msmpeg4v2_encoder_select="h263_encoder" @@ -2560,8 +2578,9 @@ on2avc_decoder_select="mdct" opus_decoder_deps="swresample" opus_decoder_select="mdct15" opus_encoder_select="audio_frame_queue mdct15" -png_decoder_select="zlib" -png_encoder_select="llvidencdsp zlib" +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" @@ -2570,7 +2589,7 @@ ra_144_decoder_select="audiodsp" ra_144_encoder_select="audio_frame_queue lpc audiodsp" ralf_decoder_select="golomb" rawvideo_decoder_select="bswapdsp" -rscc_decoder_select="zlib" +rscc_decoder_deps="zlib" rtjpeg_decoder_select="me_cmp" rv10_decoder_select="h263_decoder" rv10_encoder_select="h263_encoder" @@ -2578,7 +2597,7 @@ 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_select="zlib" +screenpresso_decoder_deps="zlib" shorten_decoder_select="bswapdsp" sipr_decoder_select="lsp" snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp" @@ -2587,13 +2606,14 @@ sonic_decoder_select="golomb rangecoder" sonic_encoder_select="golomb rangecoder" sonic_ls_encoder_select="golomb rangecoder" sp5x_decoder_select="mjpeg_decoder" -srgc_decoder_select="zlib" +srgc_decoder_deps="zlib" svq1_decoder_select="hpeldsp" svq1_encoder_select="aandcttables hpeldsp me_cmp mpegvideoenc" svq3_decoder_select="golomb h264dsp h264parse h264pred hpeldsp tpeldsp videodsp" svq3_decoder_suggest="zlib" tak_decoder_select="audiodsp" -tdsc_decoder_select="zlib mjpeg_decoder" +tdsc_decoder_deps="zlib" +tdsc_decoder_select="mjpeg_decoder" theora_decoder_select="vp3_decoder" thp_decoder_select="mjpeg_decoder" tiff_decoder_suggest="zlib lzma" @@ -2602,15 +2622,13 @@ truehd_decoder_select="mlp_parser" truehd_encoder_select="lpc" truemotion2_decoder_select="bswapdsp" truespeech_decoder_select="bswapdsp" -tscc_decoder_select="zlib" +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" -vc1_qsv_decoder_deps="libmfx" -vc1_qsv_decoder_select="qsvdec vc1_qsv_hwaccel vc1_parser" vc1image_decoder_select="vc1_decoder" vorbis_decoder_select="mdct" vorbis_encoder_select="mdct" @@ -2621,7 +2639,7 @@ 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_decoder_select="videodsp vp9_parser vp9_superframe_split_bsf" webp_decoder_select="vp8_decoder exif" wmalossless_decoder_select="llauddsp" wmapro_decoder_select="mdct sinewin wma_freqs" @@ -2638,23 +2656,19 @@ wmv3_decoder_select="vc1_decoder" wmv3image_decoder_select="wmv3_decoder" xma1_decoder_select="wmapro_decoder" xma2_decoder_select="wmapro_decoder" -zerocodec_decoder_select="zlib" -zlib_decoder_select="zlib" -zlib_encoder_select="zlib" -zmbv_decoder_select="zlib" -zmbv_encoder_select="zlib" +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_any="libdl LoadLibrary" cuvid_deps="cuda" -d3d11va_deps="d3d11_h dxva_h ID3D11VideoDecoder ID3D11VideoContext" -dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32" -dxva2_extralibs="-luser32" -vda_framework_deps="VideoDecodeAcceleration_VDADecoder_h blocks_extension" -vda_framework_extralibs="-framework VideoDecodeAcceleration" -vda_deps="vda_framework pthreads" -vda_extralibs="-framework CoreFoundation -framework QuartzCore" +d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" +dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" +nvdec_deps="cuda" videotoolbox_hwaccel_deps="videotoolbox pthreads" videotoolbox_hwaccel_extralibs="-framework QuartzCore" xvmc_deps="X11_extensions_XvMClib_h" @@ -2663,67 +2677,52 @@ h263_vaapi_hwaccel_deps="vaapi" h263_vaapi_hwaccel_select="h263_decoder" h263_videotoolbox_hwaccel_deps="videotoolbox" h263_videotoolbox_hwaccel_select="h263_decoder" -h264_cuvid_hwaccel_deps="cuda cuvid" -h264_cuvid_hwaccel_select="h264_cuvid_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_mediacodec_hwaccel_deps="mediacodec" -h264_mmal_hwaccel_deps="mmal" -h264_qsv_hwaccel_deps="libmfx" +h264_nvdec_hwaccel_deps="nvdec" +h264_nvdec_hwaccel_select="h264_decoder" h264_vaapi_hwaccel_deps="vaapi" h264_vaapi_hwaccel_select="h264_decoder" -h264_vda_hwaccel_deps="vda" -h264_vda_hwaccel_select="h264_decoder" -h264_vda_old_hwaccel_deps="vda" -h264_vda_old_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_cuvid_hwaccel_deps="cuda cuvid" -hevc_cuvid_hwaccel_select="hevc_cuvid_decoder" hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" hevc_d3d11va_hwaccel_select="hevc_decoder" -hevc_mediacodec_hwaccel_deps="mediacodec" 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_qsv_hwaccel_deps="libmfx" +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_cuvid_hwaccel_deps="cuda cuvid" -mjpeg_cuvid_hwaccel_select="mjpeg_cuvid_decoder" mpeg_xvmc_hwaccel_deps="xvmc" mpeg_xvmc_hwaccel_select="mpeg2video_decoder" -mpeg1_cuvid_hwaccel_deps="cuda cuvid" -mpeg1_cuvid_hwaccel_select="mpeg1_cuvid_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_cuvid_hwaccel_deps="cuda cuvid" -mpeg2_cuvid_hwaccel_select="mpeg2_cuvid_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_mediacodec_hwaccel_deps="mediacodec" -mpeg2_mmal_hwaccel_deps="mmal" -mpeg2_qsv_hwaccel_deps="libmfx" -mpeg2_qsv_hwaccel_select="qsvdec_mpeg2" +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" @@ -2732,57 +2731,54 @@ mpeg2_videotoolbox_hwaccel_deps="videotoolbox" mpeg2_videotoolbox_hwaccel_select="mpeg2video_decoder" mpeg2_xvmc_hwaccel_deps="xvmc" mpeg2_xvmc_hwaccel_select="mpeg2video_decoder" -mpeg4_cuvid_hwaccel_deps="cuda cuvid" -mpeg4_cuvid_hwaccel_select="mpeg4_cuvid_decoder" -mpeg4_mediacodec_hwaccel_deps="mediacodec" -mpeg4_mmal_hwaccel_deps="mmal" +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_cuvid_hwaccel_deps="cuda cuvid" -vc1_cuvid_hwaccel_select="vc1_cuvid_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_mmal_hwaccel_deps="mmal" -vc1_qsv_hwaccel_deps="libmfx" -vc1_qsv_hwaccel_select="qsvdec_vc1" +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_cuvid_hwaccel_deps="cuda cuvid" -vp8_cuvid_hwaccel_select="vp8_cuvid_decoder" -vp9_cuvid_hwaccel_deps="cuda cuvid" -vp9_cuvid_hwaccel_select="vp9_cuvid_decoder" -vp8_mediacodec_hwaccel_deps="mediacodec" -vp8_qsv_hwaccel_deps="libmfx" +vp8_nvdec_hwaccel_deps="nvdec" +vp8_nvdec_hwaccel_select="vp8_decoder" +vp8_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVP8" +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_mediacodec_hwaccel_deps="mediacodec" +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_any="linux_videodev2_h" @@ -2791,106 +2787,93 @@ scale_npp_filter_deps="cuda libnpp" scale_cuda_filter_deps="cuda_sdk" thumbnail_cuda_filter_deps="cuda_sdk" +amf_deps_any="libdl LoadLibrary" nvenc_deps="cuda" 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="cuda cuvid" +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_deps="libmfx" -h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec h264_qsv_hwaccel" -h264_qsv_encoder_deps="libmfx" +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_deps="VAEncPictureParameterBufferH264" -h264_vaapi_encoder_select="vaapi_encode golomb" -h264_vda_decoder_deps="vda" -h264_vda_decoder_select="h264_decoder" -h264_vdpau_decoder_deps="vdpau" -h264_vdpau_decoder_select="h264_decoder" +h264_vaapi_encoder_select="cbs_h264 vaapi_encode" h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" -hevc_cuvid_decoder_deps="cuda cuvid" +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_deps="libmfx" -hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec hevc_qsv_hwaccel" -hevc_qsv_encoder_deps="libmfx" +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="vaapi_encode golomb" +hevc_vaapi_encoder_select="cbs_h265 vaapi_encode" hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" hevc_v4l2m2m_encoder_deps="v4l2_m2m hevc_v4l2_m2m" -mjpeg_cuvid_decoder_deps="cuda cuvid" +mjpeg_cuvid_decoder_deps="cuvid" +mjpeg_qsv_encoder_deps="libmfx" +mjpeg_qsv_encoder_select="qsvenc" mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" mjpeg_vaapi_encoder_select="vaapi_encode jpegtables" -mpeg1_cuvid_decoder_deps="cuda cuvid" -mpeg1_vdpau_decoder_deps="vdpau" -mpeg1_vdpau_decoder_select="mpeg1video_decoder" +mpeg1_cuvid_decoder_deps="cuvid" mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" mpeg2_crystalhd_decoder_select="crystalhd" -mpeg2_cuvid_decoder_deps="cuda cuvid" +mpeg2_cuvid_decoder_deps="cuvid" mpeg2_mmal_decoder_deps="mmal" mpeg2_mediacodec_decoder_deps="mediacodec" -mpeg2_qsv_decoder_deps="libmfx" -mpeg2_qsv_decoder_select="qsvdec mpeg2_qsv_hwaccel" -mpeg2_qsv_encoder_deps="libmfx" +mpeg2_qsv_decoder_select="qsvdec mpegvideo_parser" mpeg2_qsv_encoder_select="qsvenc" mpeg2_vaapi_encoder_deps="VAEncPictureParameterBufferMPEG2" -mpeg2_vaapi_encoder_select="vaapi_encode" +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="cuda cuvid" +mpeg4_cuvid_decoder_deps="cuvid" mpeg4_mediacodec_decoder_deps="mediacodec" mpeg4_mmal_decoder_deps="mmal" mpeg4_omx_encoder_deps="omx" -mpeg4_vdpau_decoder_deps="vdpau" -mpeg4_vdpau_decoder_select="mpeg4_decoder" mpeg4_v4l2m2m_decoder_deps="v4l2_m2m mpeg4_v4l2_m2m" mpeg4_v4l2m2m_encoder_deps="v4l2_m2m mpeg4_v4l2_m2m" -mpeg_vdpau_decoder_deps="vdpau" -mpeg_vdpau_decoder_select="mpeg2video_decoder" 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="cuda cuvid" +vc1_cuvid_decoder_deps="cuvid" vc1_mmal_decoder_deps="mmal" -vc1_vdpau_decoder_deps="vdpau" -vc1_vdpau_decoder_select="vc1_decoder" +vc1_qsv_decoder_select="qsvdec vc1_parser" vc1_v4l2m2m_decoder_deps="v4l2_m2m vc1_v4l2_m2m" -vp8_cuvid_decoder_deps="cuda cuvid" +vp8_cuvid_decoder_deps="cuvid" vp8_mediacodec_decoder_deps="mediacodec" -vp8_qsv_decoder_deps="libmfx" -vp8_qsv_decoder_select="qsvdec vp8_qsv_hwaccel vp8_parser" +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="cuda cuvid" +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" -wmv3_vdpau_decoder_select="vc1_vdpau_decoder" # parsers +aac_parser_select="adts_header" h264_parser_select="golomb h264dsp h264parse" hevc_parser_select="hevcparse" mpegaudio_parser_select="mpegaudioheader" @@ -2899,10 +2882,17 @@ mpeg4video_parser_select="h263dsp mpegvideo qpeldsp" vc1_parser_select="vc1dsp" # bitstream_filters +aac_adtstoasc_bsf_select="adts_header" +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_h264 cbs_h265 cbs_mpeg2" # 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" @@ -2938,6 +2928,8 @@ 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" libcelt_decoder_deps="libcelt" libfdk_aac_decoder_deps="libfdk_aac" libfdk_aac_encoder_deps="libfdk_aac" @@ -2976,7 +2968,7 @@ libtheora_encoder_deps="libtheora" libtwolame_encoder_deps="libtwolame" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" libvorbis_decoder_deps="libvorbis" -libvorbis_encoder_deps="libvorbis" +libvorbis_encoder_deps="libvorbis libvorbisenc" libvorbis_encoder_select="audio_frame_queue" libvpx_vp8_decoder_deps="libvpx" libvpx_vp8_encoder_deps="libvpx" @@ -2994,9 +2986,9 @@ libx265_encoder_deps="libx265" libxavs_encoder_deps="libxavs" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" -videotoolbox_extralibs="-framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework CoreVideo" +videotoolbox_suggest="coreservices" +videotoolbox_deps="corefoundation coremedia corevideo" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" -videotoolbox_encoder_suggest="vda_framework" # demuxers / muxers ac3_demuxer_select="ac3_parser" @@ -3023,6 +3015,7 @@ 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" @@ -3059,7 +3052,8 @@ sap_demuxer_select="sdp_demuxer" sap_muxer_select="rtp_muxer rtp_protocol rtpenc_chain" sdp_demuxer_select="rtpdec" smoothstreaming_muxer_select="ismv_muxer" -spdif_muxer_select="aac_parser" +spdif_demuxer_select="adts_header" +spdif_muxer_select="adts_header" spx_muxer_select="ogg_muxer" swf_demuxer_suggest="zlib" tak_demuxer_select="tak_parser" @@ -3080,8 +3074,9 @@ xwma_demuxer_select="riffdec" # indevs / outdevs alsa_indev_deps="alsa" alsa_outdev_deps="alsa" -avfoundation_indev_deps="avfoundation pthreads" -avfoundation_indev_extralibs="-framework Foundation -framework CoreVideo -framework CoreMedia" +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" @@ -3101,26 +3096,28 @@ gdigrab_indev_deps="CreateDIBSection" gdigrab_indev_extralibs="-lgdi32" gdigrab_indev_select="bmp_decoder" iec61883_indev_deps="libiec61883" -jack_indev_deps="jack" +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" -libv4l2_indev_deps="libv4l2" openal_indev_deps="openal" opengl_outdev_deps="opengl" -oss_indev_deps_any="soundcard_h sys_soundcard_h" -oss_outdev_deps_any="soundcard_h sys_soundcard_h" +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="X11_extensions_Xvlib_h XvGetPortAttribute" xv_outdev_extralibs="-lXv -lX11 -lXext" @@ -3135,8 +3132,11 @@ 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" librtmp_protocol_deps="librtmp" librtmpe_protocol_deps="librtmp" @@ -3145,32 +3145,32 @@ librtmpt_protocol_deps="librtmp" librtmpte_protocol_deps="librtmp" libsmbclient_protocol_deps="libsmbclient gplv3" libssh_protocol_deps="libssh" +libtls_conflict="openssl gnutls" 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" sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags" sctp_protocol_select="network" +securetransport_conflict="openssl gnutls libtls" srtp_protocol_select="rtp_protocol srtp" tcp_protocol_select="network" -tls_gnutls_protocol_conflict="tls_schannel_protocol tls_securetransport_protocol" -tls_gnutls_protocol_deps="gnutls" -tls_gnutls_protocol_select="tcp_protocol" -tls_openssl_protocol_conflict="tls_schannel_protocol tls_securetransport_protocol tls_gnutls_protocol" -tls_openssl_protocol_deps="openssl" -tls_openssl_protocol_select="tcp_protocol" -tls_schannel_protocol_deps="schannel" -tls_schannel_protocol_select="tcp_protocol" -tls_securetransport_protocol_deps="securetransport" -tls_securetransport_protocol_select="tcp_protocol" -tls_protocol_deps_any="tls_schannel_protocol tls_securetransport_protocol tls_gnutls_protocol tls_openssl_protocol" +tls_protocol_deps_any="gnutls openssl schannel securetransport libtls" +tls_protocol_select="tcp_protocol" udp_protocol_select="network" udplite_protocol_select="network" unix_protocol_deps="sys_un_h" @@ -3191,17 +3191,22 @@ blackframe_filter_deps="gpl" boxblur_filter_deps="gpl" bs2b_filter_deps="libbs2b" colormatrix_filter_deps="gpl" +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" deshake_filter_select="pixelutils" drawtext_filter_deps="libfreetype" +drawtext_filter_suggest="libfontconfig libfribidi" elbg_filter_deps="avcodec" eq_filter_deps="gpl" fftfilt_filter_deps="avcodec" @@ -3220,6 +3225,7 @@ hqdn3d_filter_deps="gpl" interlace_filter_deps="gpl" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" +lv2_filter_deps="lv2" mcdeint_filter_deps="avcodec gpl" movie_filter_deps="avcodec avformat" mpdecimate_filter_deps="gpl" @@ -3229,12 +3235,17 @@ negate_filter_deps="lut_filter" 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" +program_opencl_filter_deps="opencl" pullup_filter_deps="gpl" removelogo_filter_deps="avcodec avformat swscale" repeatfields_filter_deps="gpl" @@ -3246,6 +3257,7 @@ scale_filter_deps="swscale" scale_qsv_filter_deps="libmfx" select_filter_select="pixelutils" showcqt_filter_deps="avcodec avformat swscale" +showcqt_filter_suggest="libfontconfig libfreetype" showcqt_filter_select="fft" showfreqs_filter_deps="avcodec" showfreqs_filter_select="fft" @@ -3269,15 +3281,18 @@ tinterlace_filter_deps="gpl" tinterlace_merge_test_deps="tinterlace_filter" tinterlace_pad_test_deps="tinterlace_filter" tonemap_filter_deps="const_nan" +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" +libvmaf_filter_deps="libvmaf pthreads" zmq_filter_deps="libzmq" zoompan_filter_deps="swscale" zscale_filter_deps="libzimg const_nan" scale_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +vpp_qsv_filter_deps="libmfx" +vpp_qsv_filter_select="qsvvpp" # examples avio_dir_cmd_deps="avformat avutil" @@ -3301,30 +3316,47 @@ 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" + +# EXTRALIBS_LIST +cpu_init_extralibs="pthreads_extralibs" +cws2fws_extralibs="zlib_extralibs" # libraries, in linking 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="network" +avformat_suggest="libm network zlib" avresample_deps="avutil" +avresample_suggest="libm" +avutil_suggest="clock_gettime cuda libm libdrm libmfx opencl user32 vaapi videotoolbox corefoundation corevideo coremedia wincrypt" 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" +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 swresample" ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter null_filter trim_filter" +ffmpeg_suggest="ole32 psapi shell32" ffplay_deps="avcodec avformat swscale swresample sdl2" -ffplay_extralibs='$sdl2_extralibs' ffplay_select="rdft crop_filter transpose_filter hflip_filter vflip_filter rotate_filter" +ffplay_suggest="shell32" ffprobe_deps="avcodec avformat" -ffserver_deps="avformat fork sarestart" -ffserver_select="ffm_muxer rtp_protocol rtsp_demuxer" +ffprobe_suggest="shell32" # documentation podpages_deps="perl" @@ -3360,6 +3392,7 @@ pkg_config_default=pkg-config ranlib_default="ranlib" strip_default="strip" version_script='--version-script' +objformat="elf32" x86asmexe_default="nasm" windres_default="windres" nvcc_default="nvcc" @@ -3401,6 +3434,12 @@ 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" @@ -3483,7 +3522,6 @@ find_things(){ ENCODER_LIST=$(find_things encoder ENC libavcodec/allcodecs.c) DECODER_LIST=$(find_things decoder DEC libavcodec/allcodecs.c) -HWACCEL_LIST=$(find_things hwaccel HWACCEL libavcodec/allcodecs.c) PARSER_LIST=$(find_things parser PARSER libavcodec/allcodecs.c) MUXER_LIST=$(find_things muxer _MUX libavformat/allformats.c) DEMUXER_LIST=$(find_things demuxer DEMUX libavformat/allformats.c) @@ -3499,22 +3537,39 @@ find_things_extern(){ } 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) -ALL_COMPONENTS=" +AVCODEC_COMPONENTS_LIST=" $BSF_LIST $DECODER_LIST - $DEMUXER_LIST $ENCODER_LIST - $FILTER_LIST $HWACCEL_LIST - $INDEV_LIST - $MUXER_LIST - $OUTDEV_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 @@ -3571,8 +3626,13 @@ for opt do --extra-ldexeflags=*) add_ldexeflags $optval ;; + --extra-ldsoflags=*) + add_ldsoflags $optval + ;; --extra-ldlibflags=*) - add_ldlibflags $optval + 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 @@ -3688,6 +3748,19 @@ 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 </dev/null | head -n1) _cflags_speed='-O5' _cflags_size='-O5 -qcompact' - elif $_cc -V 2>/dev/null | grep -q Compaq; then - _type=ccc - _ident=$($_cc -V | head -n1 | cut -d' ' -f1-3) - _DEPFLAGS='-M' - _cflags_speed='-fast' - _cflags_size='-O1' - _flags_filter=ccc_flags elif $_cc --vsn 2>/dev/null | grep -Eq "ARM (C/C\+\+ )?Compiler"; then test -d "$sysroot" || die "No valid sysroot specified." _type=armcc @@ -4200,16 +4213,6 @@ probe_cc(){ _depflags='-MMD' _cflags_speed='-O3' _cflags_size='-Os' - elif $_cc -version 2>/dev/null | grep -Eq 'TMS470|TI ARM'; then - _type=tms470 - _ident=$($_cc -version | head -n1 | tr -s ' ') - _flags='--gcc --abi=eabi -me' - _cc_e='-ppl -fe=$@' - _cc_o='-fe=$@' - _depflags='-ppa -ppd=$(@:.o=.d)' - _cflags_speed='-O3 -mf=5' - _cflags_size='-O3 -mf=2' - _flags_filter=tms470_flags elif $_cc -v 2>&1 | grep -q clang; then _type=clang _ident=$($_cc --version 2>/dev/null | head -n1) @@ -4239,14 +4242,6 @@ probe_cc(){ _cflags_speed='-O2' _cflags_size='-Os' _flags_filter='filter_out -Wdisabled-optimization|-Wtype-limits|-fno-signed-zeros' - elif $_cc -V 2>&1 | grep -q Portland; then - _type=pgi - _ident="PGI $($_cc -V 2>&1 | awk '/^pgcc/ { print $2; exit }')" - opt_common='-alias=ansi -Mdse -Mlre -Mpre' - _cflags_speed="-O3 -Mautoinline -Munroll=c:4 $opt_common" - _cflags_size="-O2 -Munroll=c:1 $opt_common" - _cflags_noopt="-O" - _flags_filter=pgi_flags elif $_cc 2>&1 | grep -q 'Microsoft.*ARM.*Assembler'; then _type=armasm _ident=$($_cc | head -n1) @@ -4395,12 +4390,6 @@ fi if $ar 2>&1 | grep -q Microsoft; then arflags="-nologo" ar_o='-out:$@' -elif $ar 2>&1 | grep -q 'Texas Instruments'; then - arflags="rq" - ar_o='$@' -elif $ar 2>&1 | grep -q 'Usage: ar.*-X.*any'; then - arflags='-Xany -r -c' - ar_o='$@' elif $ar 2>&1 | grep -q "\[D\] "; then arflags="rcD" ar_o='$@' @@ -4419,13 +4408,6 @@ if test -n "$sysroot"; then gcc|llvm_gcc|clang) add_cppflags --sysroot="$sysroot" add_ldflags --sysroot="$sysroot" -# On Darwin --sysroot may be ignored, -isysroot always affects headers and linking - add_cppflags -isysroot "$sysroot" - add_ldflags -isysroot "$sysroot" - ;; - tms470) - add_cppflags -I"$sysinclude" - add_ldflags --sysroot="$sysroot" ;; esac fi @@ -4546,6 +4528,7 @@ elif enabled arm; then 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 @@ -4637,7 +4620,7 @@ elif enabled mips; then loongson*) enable loongson2 enable loongson3 - enable local_aligned_8 local_aligned_16 local_aligned_32 + enable local_aligned enable simd_align_16 enable fast_64bit enable fast_clz @@ -4854,59 +4837,52 @@ check_64bit(){ expr=$3 check_code cc "" "int test[2*($expr) - 1]" && subarch=$arch64 || subarch=$arch32 + enable $subarch } case "$arch" in aarch64|alpha|ia64) - spic=$shared + enabled shared && enable_weak pic ;; mips) check_64bit mips mips64 '_MIPS_SIM > 1' - spic=$shared + enabled shared && enable_weak pic ;; parisc) check_64bit parisc parisc64 'sizeof(void *) > 4' - spic=$shared + enabled shared && enable_weak pic ;; ppc) check_64bit ppc ppc64 'sizeof(void *) > 4' - spic=$shared + enabled shared && enable_weak pic ;; s390) check_64bit s390 s390x 'sizeof(void *) > 4' - spic=$shared + enabled shared && enable_weak pic ;; sparc) check_64bit sparc sparc64 'sizeof(void *) > 4' - spic=$shared + enabled shared && enable_weak pic ;; x86) check_64bit x86_32 x86_64 'sizeof(void *) > 4' - # Treat x32 as x64 for now. Note it also needs spic=$shared + # Treat x32 as x64 for now. Note it also needs pic if shared test "$subarch" = "x86_32" && check_cpp_condition stddef.h 'defined(__x86_64__)' && - subarch=x86_64 - if test "$subarch" = "x86_64"; then - spic=$shared + subarch=x86_64 && enable x86_64 && disable x86_32 + if enabled x86_64; then + enabled shared && enable_weak pic + objformat=elf64 fi ;; - ppc) - check_cc < $$(@:$(SLIBSUF)=.def); lib.exe -nologo -machine:$(LIBTARGET) -def:$$(@:$(SLIBSUF)=.def) -out:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' - if enabled x86_64; then - LIBTARGET=x64 - fi - elif check_cmd $dlltool --version; then - SLIB_EXTRA_CMD=-'sed -e "s/ @[^ ]*//" $$(@:$(SLIBSUF)=.orig.def) > $$(@:$(SLIBSUF)=.def); $(DLLTOOL) -m $(LIBTARGET) -d $$(@:$(SLIBSUF)=.def) -l $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib) -D $(SLIBNAME_WITH_MAJOR)' - fi + SLIB_EXTRA_CMD='cp $(SUBDIR)lib$(SLIBNAME:$(SLIBSUF)=.dll.a) $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' 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)' - SHFLAGS='-shared -Wl,--output-def,$$(@:$(SLIBSUF)=.orig.def) -Wl,--out-implib,$(SUBDIR)lib$(SLIBNAME:$(SLIBSUF)=.dll.a) -Wl,--enable-runtime-pseudo-reloc -Wl,--disable-auto-image-base' + 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" ranlib=: enable dos_paths @@ -5049,7 +5016,7 @@ case $target_os in SLIBSUF=".dll" SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' - SLIB_CREATE_DEF_CMD='$(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' + 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)' @@ -5135,9 +5102,6 @@ case $target_os in -l:drtaeabi.dso -l:scppnwdl.dso -lsupc++ -lgcc \ -l:libc.dso -l:libm.dso -l:euser.dso -l:libcrt0.lib ;; - osf1) - add_cppflags -D_OSF_SOURCE -D_POSIX_PII -D_REENTRANT - ;; minix) ;; none) @@ -5193,6 +5157,8 @@ probe_libc(){ 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__ + check_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && + add_${pfx}cppflags -D_WIN32_WINNT=0x0600 elif check_${pfx}cpp_condition _mingw.h "defined __MINGW_VERSION" || check_${pfx}cpp_condition _mingw.h "defined __MINGW32_VERSION"; then eval ${pfx}libc_type=mingw32 @@ -5200,10 +5166,10 @@ probe_libc(){ (__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 - check_${pfx}cpp_condition _mingw.h "defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0502" || - add_${pfx}cppflags -D_WIN32_WINNT=0x0502 check_${pfx}cpp_condition _mingw.h "__MSVCRT_VERSION__ < 0x0700" && add_${pfx}cppflags -D__MSVCRT_VERSION__=0x0700 + check_${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__ elif check_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then @@ -5223,14 +5189,14 @@ probe_libc(){ # 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 XP unless the user has + # 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.) check_${pfx}cpp_condition stdlib.h "defined(_WIN32_WINNT)" || - { check_${pfx}cpp < #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -5259,12 +5225,11 @@ test "$?" != 0 && check_${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 -test -n "$libc_type" && enable libc_$libc_type probe_libc host_ -test -n "$host_libc_type" && enable host_libc_$host_libc_type # hacks for compiler/libc/os combinations @@ -5272,28 +5237,11 @@ case $libc_type in bionic) add_compat strtod.o strtod=avpriv_strtod ;; - glibc) - if enabled tms470; then - CPPFLAGS="-I${source_path}/compat/tms470 ${CPPFLAGS}" - add_cppflags -D__USER_LABEL_PREFIX__= - add_cppflags -D__builtin_memset=memset - add_cppflags -D__gnuc_va_list=va_list -D_VA_LIST_DEFINED - add_cflags -pds=48 # incompatible redefinition of macro - elif enabled ccc; then - add_ldflags -Wl,-z,now # calls to libots crash without this - fi - ;; esac check_compile_assert flt_lim "float.h limits.h" "DBL_MAX == (double)DBL_MAX" || add_cppflags '-I\$(SRC_PATH)/compat/float' -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 - check_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable_weak pic set_default libdir @@ -5303,17 +5251,6 @@ set_default libdir set_default $PATHS_LIST set_default nm -# we need to build at least one lib type -if ! enabled_any static shared; then - cat <= 0x0a060100" || die "ERROR: Decklink API version must be >= 10.6.1."; } } @@ -5908,6 +5827,7 @@ 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_header jni.h && enabled pthreads || die "ERROR: jni not found"; } enabled ladspa && require_header ladspa.h +enabled lv2 && require_pkg_config lv2 lilv-0 "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 @@ -5918,21 +5838,21 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas 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 && { use_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || +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 libfreetype2 freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType +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 && { use_pkg_config libgme libgme gme/gme.h gme_new_emu || +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 +enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc $pthreads_extralibs enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 0.8.1" kvazaar.h kvz_api_get # 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 @@ -5940,32 +5860,24 @@ enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 0.8.1" kv # 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 && { use_pkg_config libmfx libmfx "mfx/mfxvideo.h" MFXInit || - { require libmfx "mfx/mfxvideo.h" MFXInit -llibmfx && warn "using libmfx without pkg-config"; } } +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 -enabled libmysofa && require libmysofa "mysofa.h" mysofa_load -lmysofa +enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs +enabled libmysofa && require libmysofa "mysofa.h" mysofa_load -lmysofa $zlib_extralibs enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc || check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppc || 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_header opencv2/core/core_c.h && - { use_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader || - require opencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || + { 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_lib libopenjpeg openjpeg-2.3/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - check_lib libopenjpeg openjpeg-2.3/openjpeg.h opj_version -lopenjp2 || - { check_lib libopenjpeg openjpeg-2.2/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - check_lib libopenjpeg openjpeg-2.2/openjpeg.h opj_version -lopenjp2 || - { check_lib libopenjpeg openjpeg-2.1/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - check_lib libopenjpeg openjpeg-2.1/openjpeg.h opj_version -lopenjp2 || - { check_lib libopenjpeg openjpeg-2.0/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - { check_lib libopenjpeg openjpeg-1.5/openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - { check_lib libopenjpeg openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - die "ERROR: libopenjpeg not found"; } -enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create +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 @@ -5977,44 +5889,45 @@ enabled libopus && { 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 +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 && { use_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || - require smbclient libsmbclient.h smbc_init -lsmbclient; } -enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnappy -enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr && LIBSOXR="-lsoxr" +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 -lspeex +enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init 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 libvmaf.h compute_vmaf +enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 0.6.2" 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 && { - use_pkg_config libvpx_vp8_decoder "vpx >= 0.9.1" "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_dec_init_ver -lvpx || - die "ERROR: libvpx decoder version must be >=0.9.1"; + 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_dec_init_ver VPX_IMG_FMT_HIGHBITDEPTH" -lvpx || + die "ERROR: libvpx decoder version must be >=1.4.0"; } enabled libvpx_vp8_encoder && { - use_pkg_config libvpx_vp8_encoder "vpx >= 0.9.7" "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_enc_init_ver VP8E_SET_MAX_INTRA_BITRATE_PCT" -lvpx || - die "ERROR: libvpx encoder version must be >=0.9.7"; + 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_enc_init_ver VPX_IMG_FMT_HIGHBITDEPTH" -lvpx || + die "ERROR: libvpx encoder version must be >=1.4.0"; } enabled libvpx_vp9_decoder && { - use_pkg_config libvpx_vp9_decoder "vpx >= 1.3.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" -lvpx + 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" } enabled libvpx_vp9_encoder && { - use_pkg_config libvpx_vp9_encoder "vpx >= 1.3.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 VP9E_SET_AQ_MODE" -lvpx + 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" } if disabled_all libvpx_vp8_decoder libvpx_vp9_decoder libvpx_vp8_encoder libvpx_vp9_encoder; then die "libvpx enabled but no supported decoders found" @@ -6024,20 +5937,20 @@ enabled libvpx && { 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 && use_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } -enabled libx264 && { use_pkg_config libx264 x264 "stdint.h x264.h" x264_encoder_encode || - { require libx264 "stdint.h x264.h" x264_encoder_encode -lx264 && + 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 x264.h "X264_BUILD >= 118" && { check_cpp_condition x264.h "X264_MPEG2" && enable libx262; } enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get && require_cpp_condition x265.h "X265_BUILD >= 68" -enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode -lxavs +enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore -enabled libzimg && require_pkg_config libzimg "zimg >= 2.3.0" zimg.h zimg_get_api_version +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 libzvbi libzvbi.h vbi_decoder_new -lzvbi && +enabled libzvbi && require_pkg_config libzvbi zvbi-0.2 libzvbi.h vbi_decoder_new && { check_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 @@ -6066,20 +5979,18 @@ enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" || die "ERROR: opengl not found." } +enabled omx && require_header OMX_Core.h enabled omx_rpi && { check_header OMX_Core.h || { ! enabled cross_compile && add_cflags -isystem/opt/vc/include/IL && check_header OMX_Core.h ; } || - die "ERROR: OpenMAX IL headers not found"; } -enabled omx && require_header OMX_Core.h -enabled openssl && { use_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || - use_pkg_config openssl openssl openssl/ssl.h SSL_library_init || + 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 rkmpp && { { require_pkg_config rockchip_mpp rockchip_mpp rockchip/rk_mpi.h mpp_create || - die "ERROR : Rockchip MPP was not found."; } && - { check_func_headers rockchip/rk_mpi_cmd.h "MPP_DEC_GET_FREE_PACKET_SLOT_COUNT" || - die "ERROR: Rockchip MPP is outdated, please get a more recent one."; } && +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"; } } @@ -6091,7 +6002,7 @@ if enabled gcrypt; then 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 && add_extralibs $gcrypt_extralibs + add_cflags $gcrypt_cflags else require gcrypt gcrypt.h gcry_mpi_new -lgcrypt fi @@ -6099,22 +6010,19 @@ fi if enabled sdl2; then SDL2_CONFIG="${cross_prefix}sdl2-config" - if check_pkg_config sdl2 "sdl2 >= 2.0.1 sdl2 < 2.1.0" SDL_events.h SDL_PollEvent; then - check_func SDL_Init $sdl2_extralibs $sdl2_cflags || - disable sdl2 - elif "${SDL2_CONFIG}" --version > /dev/null 2>&1; then + 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) check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x020001" $sdl2_cflags && check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x020100" $sdl2_cflags && - check_func SDL_Init $sdl2_extralibs $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 -enabled sdl2 && add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) && add_extralibs $sdl2_extralibs if enabled decklink; then case $target_os in @@ -6127,13 +6035,16 @@ fi enabled securetransport && check_func SecIdentityCreate "-Wl,-framework,CoreFoundation -Wl,-framework,Security" && - check_lib securetransport "Security/SecureTransport.h Security/Security.h" "SSLCreateContext SecItemImport" "-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 && check_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" && - add_extralibs -lsecur32 || + schannel_extralibs="-lsecur32" || disable schannel makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo @@ -6148,7 +6059,7 @@ rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || d # check V4L2 codecs available in the API check_header linux/fb.h check_header linux/videodev2.h -check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete +check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete check_code cc linux/videodev2.h "int i = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M | V4L2_BUF_FLAG_LAST;" || disable v4l2_m2m check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_VC1_ANNEX_G;" && enable vc1_v4l2_m2m check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG1;" && enable mpeg1_v4l2_m2m @@ -6161,7 +6072,7 @@ check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_VP8;" && enable vp8_v4l2_m check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" && enable vp9_v4l2_m2m check_header sys/videoio.h -check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete +check_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 @@ -6172,32 +6083,31 @@ check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_def check_type "dshow.h" IBaseFilter # check for ioctl_meteor.h, ioctl_bt848.h and alternatives -{ check_header dev/bktr/ioctl_meteor.h && - check_header dev/bktr/ioctl_bt848.h; } || -{ check_header machine/ioctl_meteor.h && - check_header machine/ioctl_bt848.h; } || -{ check_header dev/video/meteor/ioctl_meteor.h && - check_header dev/video/bktr/ioctl_bt848.h; } || -check_header dev/ic/bt8xx.h +check_header "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || + check_header "machine/ioctl_meteor.h machine/ioctl_bt848.h" || + check_header "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || + check_header "dev/ic/bt8xx.h" if check_struct sys/soundcard.h audio_buf_info bytes; then - enable_safe sys/soundcard.h + enable_sanitized sys/soundcard.h else - check_cc -D__BSD_VISIBLE -D__XSI_VISIBLE < audio_buf_info abc; EOF fi -check_header soundcard.h -enabled alsa && check_lib alsa alsa/asoundlib.h snd_pcm_htimestamp -lasound +enabled alsa && check_pkg_config alsa alsa "alsa/asoundlib.h" snd_pcm_htimestamp || + check_lib alsa alsa/asoundlib.h snd_pcm_htimestamp -lasound -enabled jack && check_lib jack jack/jack.h jack_client_open -ljack && - check_func jack_port_get_latency_range -ljack +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" @@ -6210,9 +6120,6 @@ 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 - - add_cflags $xcb_cflags $xcb_shm_cflags $xcb_xfixes_cflags $xcb_shape_cflags - add_extralibs $xcb_extralibs $xcb_shm_extralibs $xcb_xfixes_extralibs $xcb_shape_extralibs fi check_func_headers "windows.h" CreateDIBSection "$gdigrab_indev_extralibs" @@ -6249,6 +6156,30 @@ enabled vaapi && check_cpp_condition "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" && enable vaapi_1 +if enabled_all opencl vaapi ; then + check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" && + enable opencl_vaapi_beignet + if enabled libmfx ; then + check_type "CL/cl.h CL/va_ext.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 + +if enabled_all opencl libdrm ; then + check_func_headers "CL/cl_ext.h" clImportMemoryARM && + enable opencl_drm_arm +fi + enabled vdpau && check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" || disable vdpau @@ -6263,11 +6194,11 @@ if enabled x86; then mingw32*|mingw64*|win32|win64|linux|cygwin*) ;; *) - disable cuda cuvid nvenc + disable cuda cuvid nvdec nvenc ;; esac else - disable cuda cuvid nvenc + disable cuda cuvid nvdec nvenc fi enabled nvenc && @@ -6278,6 +6209,11 @@ 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/core/Version.h" \ + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400040001" || + disable amf + # 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 @@ -6339,8 +6275,7 @@ EOF # add some linker flags check_ldflags -Wl,--warn-common check_ldflags -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -enabled rpath && add_ldexeflags -Wl,-rpath,$libdir -enabled rpath && add_ldlibflags -Wl,-rpath,$libdir +enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic # add some strip flags @@ -6389,6 +6324,7 @@ if enabled proper_dce; then echo "X { local: *; };" > $TMPV if test_ldflags -Wl,${version_script},$TMPV; then append SHFLAGS '-Wl,${version_script},\$(SUBDIR)lib\$(NAME).ver' + quotes='""' check_cc < enable ${lib}_deps_${dep} -# -> add $dep to ${lib}_deps only once -add_dep() { - lib=$1 - dep=$2 - enabled "${lib}_deps_${dep}" && return 0 - enable "${lib}_deps_${dep}" - prepend "${lib}_deps" $dep -} - -# merge deps lib components -# merge all ${component}_deps into ${lib}_deps and ${lib}_deps_* -merge_deps() { - lib=$1 - shift - for comp in $*; do - enabled $comp || continue - eval "dep=\"\$${comp}_deps\"" - for d in $dep; do - add_dep $lib $d - done +flatten_extralibs(){ + unset nested_entries + list_name=$1 + eval list=\$${1} + for entry in $list; do + entry_copy=$entry + resolve entry_copy + append nested_entries $(filter '*_extralibs' $entry_copy) + flat_entries=$(filter_out '*_extralibs' $entry_copy) + eval $entry="\$flat_entries" done + append $list_name "$nested_entries" + + resolve nested_entries + if test -n "$(filter '*_extralibs' $nested_entries)"; then + flatten_extralibs $list_name + fi } -merge_deps libavfilter $FILTER_LIST +flatten_extralibs_wrapper(){ + list_name=$1 + flatten_extralibs $list_name + unique $list_name + resolve $list_name + eval $list_name=\$\(\$ldflags_filter \$$list_name\) + eval printf \''%s'\' \""\$$list_name"\" +} + +for linkunit in $LIBRARY_LIST; do + unset current_extralibs + eval components=\$$(toupper ${linkunit})_COMPONENTS_LIST + for comp in ${components}; do + enabled $comp || continue + comp_extralibs="${comp}_extralibs" + append current_extralibs $comp_extralibs + done + eval prepend ${linkunit}_extralibs $current_extralibs +done + +for linkunit in $LIBRARY_LIST $PROGRAM_LIST $EXTRALIBS_LIST; do + eval ${linkunit}_extralibs=\$\(flatten_extralibs_wrapper ${linkunit}_extralibs\) +done map 'enabled $v && intrinsics=${v#intrinsics_}' $INTRINSICS_LIST @@ -6633,7 +6571,7 @@ for thread in $THREADS_LIST; do fi done -if disabled stdatomic_h; then +if disabled stdatomic; then if enabled atomics_gcc; then add_cppflags '-I\$(SRC_PATH)/compat/atomics/gcc' elif enabled atomics_win32; then @@ -6663,6 +6601,8 @@ enabled amovie_filter && prepend avfilter_deps "avformat avcodec" enabled aresample_filter && prepend avfilter_deps "swresample" enabled atempo_filter && prepend avfilter_deps "avcodec" enabled cover_rect_filter && prepend avfilter_deps "avformat avcodec" +enabled convolve_filter && prepend avfilter_deps "avcodec" +enabled deconvolve_filter && prepend avfilter_deps "avcodec" enabled ebur128_filter && enabled swresample && prepend avfilter_deps "swresample" enabled elbg_filter && prepend avfilter_deps "avcodec" enabled fftfilt_filter && prepend avfilter_deps "avcodec" @@ -6691,6 +6631,9 @@ enabled zoompan_filter && prepend avfilter_deps "swscale" enabled lavfi_indev && prepend avdevice_deps "avfilter" +#FIXME +enabled sdl2_outdev && add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) + enabled opus_decoder && prepend avcodec_deps "swresample" expand_deps(){ @@ -6750,6 +6693,7 @@ if enabled x86; then echo "AESNI enabled ${aesni-no}" echo "AVX enabled ${avx-no}" echo "AVX2 enabled ${avx2-no}" + echo "AVX-512 enabled ${avx512-no}" echo "XOP enabled ${xop-no}" echo "FMA3 enabled ${fma3-no}" echo "FMA4 enabled ${fma4-no}" @@ -6804,11 +6748,11 @@ test -n "$random_seed" && echo echo "External libraries:" -print_enabled '' $EXTERNAL_LIBRARY_LIST | print_in_columns +print_enabled '' $EXTERNAL_LIBRARY_LIST $EXTERNAL_AUTODETECT_LIBRARY_LIST | print_in_columns echo echo "External libraries providing hardware acceleration:" -print_enabled '' $HWACCEL_LIBRARY_LIST | print_in_columns +print_enabled '' $HWACCEL_LIBRARY_LIST $HWACCEL_AUTODETECT_LIBRARY_LIST | print_in_columns echo echo "Libraries:" @@ -6835,12 +6779,21 @@ fi echo "License: $license" -echo "Creating configuration files ..." - fi # test "$quiet" != "yes" +if test -n "$WARNINGS"; then + printf "\n%s%s$WARNINGS%s" "$warn_color" "$bold_color" "$reset_color" + enabled fatal_warnings && exit 1 +fi + test -e Makefile || echo "include $source_path/Makefile" > 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="" @@ -6869,6 +6822,7 @@ endif CC_IDENT=$cc_ident ARCH=$arch INTRINSICS=$intrinsics +EXTERN_PREFIX=$extern_prefix CC=$cc CXX=$cxx AS=$as @@ -6884,6 +6838,8 @@ DEPX86ASMFLAGS=\$(X86ASMFLAGS) AR=$ar ARFLAGS=$arflags AR_O=$ar_o +AR_CMD=$ar +NM_CMD=$nm RANLIB=$ranlib STRIP=$strip STRIPTYPE=$striptype @@ -6912,13 +6868,12 @@ LD_O=$LD_O X86ASM_O=$X86ASM_O LD_LIB=$LD_LIB LD_PATH=$LD_PATH -DLLTOOL=$dlltool WINDRES=$windres DEPWINDRES=$dep_cc DOXYGEN=$doxygen LDFLAGS=$LDFLAGS LDEXEFLAGS=$LDEXEFLAGS -LDLIBFLAGS=$LDLIBFLAGS +LDSOFLAGS=$LDSOFLAGS SHFLAGS=$(echo $($ldflags_filter $SHFLAGS)) ASMSTRIPFLAGS=$ASMSTRIPFLAGS X86ASMFLAGS=$X86ASMFLAGS @@ -6962,12 +6917,10 @@ TARGET_PATH=$target_path TARGET_SAMPLES=${target_samples:-\$(SAMPLES)} CFLAGS-ffplay=${sdl2_cflags} CFLAGS_HEADERS=$CFLAGS_HEADERS -ZLIB=$($ldflags_filter -lz) LIB_INSTALL_EXTRA_CMD=$LIB_INSTALL_EXTRA_CMD EXTRALIBS=$extralibs COMPAT_OBJS=$compat_objs INSTALL=$install -LIBTARGET=${LIBTARGET} SLIBNAME=${SLIBNAME} SLIBNAME_WITH_VERSION=${SLIBNAME_WITH_VERSION} SLIBNAME_WITH_MAJOR=${SLIBNAME_WITH_MAJOR} @@ -6986,12 +6939,9 @@ EOF map 'eval echo "${v}_FFLIBS=\$${v}_deps" >> ffbuild/config.mak' $LIBRARY_LIST -print_program_extralibs(){ - eval "program_extralibs=\$${1}_extralibs" - eval echo "EXTRALIBS-${1}=${program_extralibs}" >> ffbuild/config.mak -} - -map 'print_program_extralibs $v' $PROGRAM_LIST +for entry in $LIBRARY_LIST $PROGRAM_LIST $EXTRALIBS_LIST; do + eval echo "EXTRALIBS-${entry}=\$${entry}_extralibs" >> ffbuild/config.mak +done cat > $TMPH < $TMPH <$TMPASM + cat > $TMPASM <> $TMPH @@ -7047,7 +6999,7 @@ touch ffbuild/.config enabled x86asm && cp_if_changed $TMPASM config.asm cat > $TMPH < ffbuild/config.sh < $TMPH <> ffbuild/config.sh + echo ${lib}_deps=\"$lib_deps\" >> $TMPH done + +cp_if_changed $TMPH ffbuild/config.sh diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 000000000..7628cecb9 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,9 @@ +/*.1 +/*.3 +/*.html +/*.pod +/config.texi +/avoptions_codec.texi +/avoptions_format.texi +/fate.txt +/print_options diff --git a/doc/APIchanges b/doc/APIchanges index 6803eaaea..d66c84252 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,19 +2,76 @@ Never assume the API of libav* to be stable unless at least 1 month has passed since the last major version increase or the API was added. The last version increases were: -libavcodec: 2015-08-28 -libavdevice: 2015-08-28 -libavfilter: 2015-08-28 -libavformat: 2015-08-28 -libavresample: 2015-08-28 -libpostproc: 2015-08-28 -libswresample: 2015-08-28 -libswscale: 2015-08-28 -libavutil: 2015-08-28 +libavcodec: 2017-10-21 +libavdevice: 2017-10-21 +libavfilter: 2017-10-21 +libavformat: 2017-10-21 +libavresample: 2017-10-21 +libpostproc: 2017-10-21 +libswresample: 2017-10-21 +libswscale: 2017-10-21 +libavutil: 2017-10-21 API changes, most recent first: +2018-01-xx - xxxxxxx - lavfi 7.11.101 - avfilter.h + Deprecate avfilter_link_get_channels(). Use av_buffersink_get_channels(). + +2017-xx-xx - xxxxxxx - lavr 4.0.0 - avresample.h + Deprecate the entire library. Merged years ago to provide compatibility + with Libav, it remained unmaintained by the FFmpeg project and duplicated + functionality provided by libswresample. + + In order to improve consistency and reduce attack surface, it has been deprecated. + Users of this library are asked to migrate to libswresample, which, as well as + providing more functionality, is faster and has higher accuracy. + +2017-xx-xx - xxxxxxx - lavc 58.9.100 - avcodec.h + Deprecate av_lockmgr_register(). You need to build FFmpeg with threading + support enabled to get basic thread-safety (which is the default build + configuration). + +2017-12-xx - xxxxxxx - lavu 56.7.100 - cpu.h + AVX-512 flags added. + +2017-xx-xx - xxxxxxx - lavc 58.8.100 - avcodec.h + The MediaCodec decoders now support AVCodecContext.hw_device_ctx. + +2017-xx-xx - xxxxxxx - lavu 56.6.100 - hwcontext.h hwcontext_mediacodec.h + Add AV_HWDEVICE_TYPE_MEDIACODEC and a new installed header with + MediaCodec-specific hwcontext definitions. + +2017-xx-xx - xxxxxxc - lavc 58.7.100 - avcodec.h + Add AV_CODEC_CAP_HARDWARE, AV_CODEC_CAP_HYBRID, and AVCodec.wrapper_name, + and mark all AVCodecs accordingly. + +2017-xx-xx - xxxxxxx - lavu 56.4.100 / 56.7.0 - stereo3d.h + Add view field to AVStereo3D structure and AVStereo3DView enum. + +2017-xx-xx - xxxxxxx - lavc 58.6.100 - avcodec.h + Add const to AVCodecContext.hwaccel. + +2017-11-xx - xxxxxxx - lavc 58.5.100 - avcodec.h + Deprecate user visibility of the AVHWAccel structure and the functions + av_register_hwaccel() and av_hwaccel_next(). + +2017-11-xx - xxxxxxx - lavc 58.4.100 - avcodec.h + Add AVCodecHWConfig and avcodec_get_hw_config(). + +2017-11-22 - 3650cb2dfa - lavu 55.3.100 - opencl.h + Remove experimental OpenCL API (av_opencl_*). + +2017-11-22 - b25d8ef0a7 - lavu 55.2.100 - hwcontext.h hwcontext_opencl.h + Add AV_HWDEVICE_TYPE_OPENCL and a new installed header with + OpenCL-specific hwcontext definitions. + +2017-11-22 - a050f56c09 - lavu 55.1.100 - pixfmt.h + Add AV_PIX_FMT_OPENCL. + +2017-11-11 - 48e4eda11d - lavc 58.3.100 - avcodec.h + Add avcodec_get_hw_frames_parameters(). + -------- 8< --------- FFmpeg 3.4 was cut here -------- 8< --------- 2017-09-28 - b6cf66ae1c - lavc 57.106.104 - avcodec.h diff --git a/doc/Doxyfile b/doc/Doxyfile index 491db00b7..089189950 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = FFmpeg # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.4 +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 2dffe021f..5efb8e0ee 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -92,6 +92,69 @@ When this option is enabled, the long-term headers are removed from the bitstream after extraction. @end table +@section h264_metadata + +Modify metadata embedded in an H.264 stream. + +@table @option +@item aud +Insert or remove AUD NAL units in all access units of the stream. + +@table @samp +@item insert +@item remove +@end table + +@item sample_aspect_ratio +Set the sample aspect ratio of the stream in the VUI parameters. + +@item video_format +@item video_full_range_flag +Set the video format in the stream (see H.264 section E.2.1 and +table E-2). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.264 section E.2.1 +and tables E-3, E-4 and E-5). + +@item chroma_sample_loc_type +Set the chroma sample location in the stream (see H.264 section +E.2.1 and figure E-1). + +@item tick_rate +Set the tick rate (num_units_in_tick / time_scale) in the VUI +parameters. This is the smallest time unit representable in the +stream, and in many cases represents the field rate of the stream +(double the frame rate). +@item fixed_frame_rate_flag +Set whether the stream has fixed framerate - typically this indicates +that the framerate is exactly half the tick rate, but the exact +meaning is dependent on interlacing and the picture structure (see +H.264 section E.2.1 and table E-6). + +@item crop_left +@item crop_right +@item crop_top +@item crop_bottom +Set the frame cropping offsets in the SPS. These values will replace +the current ones if the stream is already cropped. + +These fields are set in pixels. Note that some sizes may not be +representable if the chroma is subsampled or the stream is interlaced +(see H.264 section 7.4.2.1.1). + +@item sei_user_data +Insert a string as SEI unregistered user data. The argument must +be of the form @emph{UUID+string}, where the UUID is as hex digits +possibly separated by hyphens, and the string can be anything. + +For example, @samp{086f3693-b7b3-4f2c-9653-21492feee5b8+hello} will +insert the string ``hello'' associated with the given UUID. + +@end table + @section h264_mp4toannexb Convert an H.264 bitstream from length prefixed mode to start code @@ -111,6 +174,69 @@ ffmpeg -i INPUT.mp4 -codec copy -bsf:v h264_mp4toannexb OUTPUT.ts Please note that this filter is auto-inserted for MPEG-TS (muxer @code{mpegts}) and raw H.264 (muxer @code{h264}) output formats. +@section h264_redundant_pps + +This applies a specific fixup to some Blu-ray streams which contain +redundant PPSs modifying irrelevant parameters of the stream which +confuse other transformations which require correct extradata. + +A new single global PPS is created, and all of the redundant PPSs +within the stream are removed. + +@section hevc_metadata + +Modify metadata embedded in an HEVC stream. + +@table @option +@item aud +Insert or remove AUD NAL units in all access units of the stream. + +@table @samp +@item insert +@item remove +@end table + +@item sample_aspect_ratio +Set the sample aspect ratio in the stream in the VUI parameters. + +@item video_format +@item video_full_range_flag +Set the video format in the stream (see H.265 section E.3.1 and +table E.2). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.265 section E.3.1 +and tables E.3, E.4 and E.5). + +@item chroma_sample_loc_type +Set the chroma sample location in the stream (see H.265 section +E.3.1 and figure E.1). + +@item tick_rate +Set the tick rate in the VPS and VUI parameters (num_units_in_tick / +time_scale). Combined with @option{num_ticks_poc_diff_one}, this can +set a constant framerate in the stream. Note that it is likely to be +overridden by container parameters when the stream is in a container. + +@item num_ticks_poc_diff_one +Set poc_proportional_to_timing_flag in VPS and VUI and use this value +to set num_ticks_poc_diff_one_minus1 (see H.265 sections 7.4.3.1 and +E.3.1). Ignored if @option{tick_rate} is not also set. + +@item crop_left +@item crop_right +@item crop_top +@item crop_bottom +Set the conformance window cropping offsets in the SPS. These values +will replace the current ones if the stream is already cropped. + +These fields are set in pixels. Note that some sizes may not be +representable if the chroma is subsampled (H.265 section 7.4.3.2.1). + +@end table + @section hevc_mp4toannexb Convert an HEVC/H.265 bitstream from length prefixed mode to start code @@ -198,6 +324,42 @@ See also the @ref{text2movsub} filter. Decompress non-standard compressed MP3 audio headers. +@section mpeg2_metadata + +Modify metadata embedded in an MPEG-2 stream. + +@table @option +@item display_aspect_ratio +Set the display aspect ratio in the stream. + +The following fixed values are supported: +@table @option +@item 4/3 +@item 16/9 +@item 221/100 +@end table +Any other value will result in square pixels being signalled instead +(see H.262 section 6.3.3 and table 6-3). + +@item frame_rate +Set the frame rate in the stream. This is constructed from a table +of known values combined with a small multiplier and divisor - if +the supplied value is not exactly representable, the nearest +representable value will be used instead (see H.262 section 6.3.3 +and table 6-4). + +@item video_format +Set the video format in the stream (see H.262 section 6.3.6 and +table 6-6). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.262 section 6.3.6 +and tables 6-7, 6-8 and 6-9). + +@end table + @section mpeg4_unpack_bframes Unpack DivX-style packed B-frames. @@ -275,6 +437,14 @@ codec) with metadata headers. See also the @ref{mov2textsub} filter. +@section trace_headers + +Log trace output containing all syntax elements in the coded stream +headers (everything above the level of individual coded blocks). +This can be useful for debugging low-level stream issues. + +Supports H.264, H.265 and MPEG-2. + @section vp9_superframe Merge VP9 invisible (alt-ref) frames back into VP9 superframes. This diff --git a/doc/codecs.texi b/doc/codecs.texi index 40f64fe4c..7e2037433 100644 --- a/doc/codecs.texi +++ b/doc/codecs.texi @@ -44,12 +44,6 @@ Use 1/4 pel motion compensation. Use loop filter. @item qscale Use fixed qscale. -@item gmc -Use gmc. -@item mv0 -Always try a mb with mv=<0,0>. -@item input_preserved - @item pass1 Use internal 2pass ratecontrol in first pass mode. @item pass2 @@ -62,8 +56,6 @@ Do not draw edges. Set error[?] variables during encoding. @item truncated -@item naq -Normalize adaptive quantization. @item ildct Use interlaced DCT. @item low_delay @@ -506,21 +498,6 @@ threading operations skip motion compensation @end table -@item vismv @var{integer} (@emph{decoding,video}) -Visualize motion vectors (MVs). - -This option is deprecated, see the codecview filter instead. - -Possible values: -@table @samp -@item pf -forward predicted MVs of P-frames -@item bf -forward predicted MVs of B-frames -@item bb -backward predicted MVs of B-frames -@end table - @item cmp @var{integer} (@emph{encoding,video}) Set full pel me compare function. @@ -757,8 +734,6 @@ Set context model. @item slice_flags @var{integer} -@item xvmc_acceleration @var{integer} - @item mbd @var{integer} (@emph{encoding,video}) Set macroblock decision algorithm (high quality mode). diff --git a/doc/decoders.texi b/doc/decoders.texi index d149d2bea..a9510bdf0 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -25,13 +25,6 @@ enabled decoders. A description of some of the currently available video decoders follows. -@section hevc - -HEVC / H.265 decoder. - -Note: the @option{skip_loop_filter} option has effect only at level -@code{all}. - @section rawvideo Raw video decoder. diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 73dc0feec..608016723 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -316,6 +316,14 @@ segment index to start live streams at (negative values are from the end). @item max_reload Maximum number of times a insufficient list is attempted to be reloaded. Default value is 1000. + +@item http_persistent +Use persistent HTTP connections. Applicable only for HTTP streams. +Enabled by default. + +@item http_multiple +Use multiple HTTP connections for downloading HTTP segments. +Enabled by default for HTTP/1.1 servers. @end table @section image2 diff --git a/doc/developer.texi b/doc/developer.texi index 98540c8f9..66b246330 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -10,9 +10,7 @@ @contents -@chapter Developers Guide - -@section Notes for external developers +@chapter Notes for external developers This document is mostly useful for internal FFmpeg developers. External developers who need to use the API in their application should @@ -30,7 +28,7 @@ For more detailed legal information about the use of FFmpeg in external programs read the @file{LICENSE} file in the source tree and consult @url{https://ffmpeg.org/legal.html}. -@section Contributing +@chapter Contributing There are 3 ways by which code gets into FFmpeg. @itemize @bullet @@ -47,9 +45,9 @@ The developer making the commit and the author are responsible for their changes and should try to fix issues their commit causes. @anchor{Coding Rules} -@section Coding Rules +@chapter Coding Rules -@subsection Code formatting conventions +@section Code formatting conventions There are the following guidelines regarding the indentation in files: @@ -74,7 +72,7 @@ The presentation is one inspired by 'indent -i4 -kr -nut'. The main priority in FFmpeg is simplicity and small code size in order to minimize the bug count. -@subsection Comments +@section Comments Use the JavaDoc/Doxygen format (see examples below) so that code documentation can be generated automatically. All nontrivial functions should have a comment above them explaining what the function does, even if it is just one sentence. @@ -114,7 +112,7 @@ int myfunc(int my_parameter) ... @end example -@subsection C language features +@section C language features FFmpeg is programmed in the ISO C90 language with a few additional features from ISO C99, namely: @@ -160,7 +158,7 @@ mixing statements and declarations; GCC statement expressions (@samp{(x = (@{ int y = 4; y; @})}). @end itemize -@subsection Naming conventions +@section Naming conventions All names should be composed with underscores (_), not CamelCase. For example, @samp{avfilter_get_video_buffer} is an acceptable function name and @samp{AVFilterGetVideo} is not. The exception from this are type names, like @@ -184,7 +182,7 @@ e.g. @samp{ff_w64_demuxer}. @item For variables and functions visible outside of file scope, used internally across multiple libraries, use @code{avpriv_} as prefix, for example, -@samp{avpriv_aac_parse_header}. +@samp{avpriv_report_missing_feature}. @item Each library has its own prefix for public symbols, in addition to the @@ -204,7 +202,7 @@ letter as they are reserved by the C standard. Names starting with @code{_} are reserved at the file level and may not be used for externally visible symbols. If in doubt, just avoid names starting with @code{_} altogether. -@subsection Miscellaneous conventions +@section Miscellaneous conventions @itemize @bullet @item @@ -216,7 +214,7 @@ Casts should be used only when necessary. Unneeded parentheses should also be avoided if they don't make the code easier to understand. @end itemize -@subsection Editor configuration +@section Editor configuration In order to configure Vim to follow FFmpeg formatting conventions, paste the following snippet into your @file{.vimrc}: @example @@ -249,9 +247,9 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}: (setq c-default-style "ffmpeg") @end lisp -@section Development Policy +@chapter Development Policy -@subsection Patches/Committing +@section Patches/Committing @subheading Licenses for patches must be compatible with FFmpeg. Contributions should be licensed under the @uref{http://www.gnu.org/licenses/lgpl-2.1.html, LGPL 2.1}, @@ -350,7 +348,7 @@ time-frame (12h for build failures and security fixes, 3 days small changes, 1 week for big patches) then commit your patch if you think it is OK. Also note, the maintainer can simply ask for more time to review! -@subsection Code +@section Code @subheading API/ABI changes should be discussed before they are made. Do not change behavior of the programs (renaming options etc) or public API or ABI without first discussing it on the ffmpeg-devel mailing list. @@ -381,12 +379,29 @@ Never write to unallocated memory, never write over the end of arrays, always check values read from some untrusted source before using them as array index or other risky things. -@subsection Documentation/Other +@section Documentation/Other +@subheading Subscribe to the ffmpeg-devel mailing list. +It is important to be subscribed to the +@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel} +mailing list. Almost any non-trivial patch is to be sent there for review. +Other developers may have comments about your contribution. We expect you see +those comments, and to improve it if requested. (N.B. Experienced committers +have other channels, and may sometimes skip review for trivial fixes.) Also, +discussion here about bug fixes and FFmpeg improvements by other developers may +be helpful information for you. Finally, by being a list subscriber, your +contribution will be posted immediately to the list, without the moderation +hold which messages from non-subscribers experience. + +However, it is more important to the project that we receive your patch than +that you be subscribed to the ffmpeg-devel list. If you have a patch, and don't +want to subscribe and discuss the patch, then please do send it to the list +anyway. + @subheading Subscribe to the ffmpeg-cvslog mailing list. -It is important to do this as the diffs of all commits are sent there and -reviewed by all the other developers. Bugs and possible improvements or -general questions regarding commits are discussed there. We expect you to -react if problems with your code are uncovered. +Diffs of all commits are sent to the +@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-cvslog, ffmpeg-cvslog} +mailing list. Some developers read this list to review all code base changes +from all sources. Subscribing to this list is not mandatory. @subheading Keep the documentation up to date. Update the documentation if you change behavior or add features. If you are @@ -406,7 +421,7 @@ finding a new maintainer and also don't forget to update the @file{MAINTAINERS} We think our rules are not too hard. If you have comments, contact us. -@section Code of conduct +@chapter Code of conduct Be friendly and respectful towards others and third parties. Treat others the way you yourself want to be treated. @@ -436,7 +451,7 @@ Finally, keep in mind the immortal words of Bill and Ted, "Be excellent to each other." @anchor{Submitting patches} -@section Submitting patches +@chapter Submitting patches First, read the @ref{Coding Rules} above if you did not yet, in particular the rules regarding patch submission. @@ -485,7 +500,7 @@ Give us a few days to react. But if some time passes without reaction, send a reminder by email. Your patch should eventually be dealt with. -@section New codecs or formats checklist +@chapter New codecs or formats checklist @enumerate @item @@ -537,7 +552,7 @@ Did you make sure it compiles standalone, i.e. with @end enumerate -@section patch submission checklist +@chapter Patch submission checklist @enumerate @item @@ -650,7 +665,7 @@ Test your code with valgrind and or Address Sanitizer to ensure it's free of leaks, out of array accesses, etc. @end enumerate -@section Patch review process +@chapter Patch review process All patches posted to ffmpeg-devel will be reviewed, unless they contain a clear note that the patch is not for the git master branch. @@ -681,7 +696,7 @@ to be reviewed, please consider helping to review other patches, that is a great way to get everyone's patches reviewed sooner. @anchor{Regression tests} -@section Regression tests +@chapter Regression tests Before submitting a patch (or committing to the repository), you should at least test that you did not break anything. @@ -692,7 +707,7 @@ Running 'make fate' accomplishes this, please see @url{fate.html} for details. this case, the reference results of the regression tests shall be modified accordingly]. -@subsection Adding files to the fate-suite dataset +@section Adding files to the fate-suite dataset When there is no muxer or encoder available to generate test media for a specific test then the media has to be included in the fate-suite. @@ -703,7 +718,7 @@ Once you have a working fate test and fate sample, provide in the commit message or introductory message for the patch series that you post to the ffmpeg-devel mailing list, a direct link to download the sample media. -@subsection Visualizing Test Coverage +@section Visualizing Test Coverage The FFmpeg build system allows visualizing the test coverage in an easy manner with the coverage tools @code{gcov}/@code{lcov}. This involves @@ -730,7 +745,7 @@ You can use the command @code{make lcov-reset} to reset the coverage measurements. You will need to rerun @code{make lcov} after running a new test. -@subsection Using Valgrind +@section Using Valgrind The configure script provides a shortcut for using valgrind to spot bugs related to memory handling. Just add the option @@ -744,7 +759,7 @@ In case you need finer control over how valgrind is invoked, use the your configure line instead. @anchor{Release process} -@section Release process +@chapter Release process FFmpeg maintains a set of @strong{release branches}, which are the recommended deliverable for system integrators and distributors (such as @@ -776,7 +791,7 @@ adjustments to the symbol versioning file. Please discuss such changes on the @strong{ffmpeg-devel} mailing list in time to allow forward planning. @anchor{Criteria for Point Releases} -@subsection Criteria for Point Releases +@section Criteria for Point Releases Changes that match the following criteria are valid candidates for inclusion into a point release: @@ -800,7 +815,7 @@ point releases of the same release branch. The order for checking the rules is (1 OR 2 OR 3) AND 4. -@subsection Release Checklist +@section Release Checklist The release process involves the following steps: diff --git a/doc/doxy/.gitignore b/doc/doxy/.gitignore new file mode 100644 index 000000000..ac7af2e80 --- /dev/null +++ b/doc/doxy/.gitignore @@ -0,0 +1 @@ +/html/ diff --git a/doc/encoders.texi b/doc/encoders.texi index 431777c45..6a410a8cb 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -64,7 +64,6 @@ to find an optimal combination by adding or subtracting a specific value from all quantizers and adjusting some individual quantizer a little. Will tune itself based on whether @option{aac_is}, @option{aac_ms} and @option{aac_pns} are enabled. -This is the default choice for a coder. @item anmr Average noise to mask ratio (ANMR) trellis-based solution. @@ -77,10 +76,10 @@ Not currently recommended. @item fast Constant quantizer method. -This method sets a constant quantizer for all bands. This is the fastest of all -the methods and has no rate control or support for @option{aac_is} or -@option{aac_pns}. -Not recommended. +Uses a cheaper version of twoloop algorithm that doesn't try to do as many +clever adjustments. Worse with low bitrates (less than 64kbps), but is better +and much faster at higher bitrates. +This is the default choice for a coder @end table @@ -1681,6 +1680,13 @@ colorspaces: @end table @item row-mt @var{boolean} Enable row based multi-threading. +@item tune-content +Set content type: default (0), screen (1), film (2). +@item corpus-complexity +Corpus VBR mode is a variant of standard VBR where the complexity distribution +midpoint is passed in rather than calculated for a specific clip or chunk. + +The valid range is [0, 10000]. 0 (default) uses standard VBR. @end table @end table diff --git a/doc/examples/.gitignore b/doc/examples/.gitignore new file mode 100644 index 000000000..154c8415f --- /dev/null +++ b/doc/examples/.gitignore @@ -0,0 +1,22 @@ +/avio_dir_cmd +/avio_reading +/decode_audio +/decode_video +/demuxing_decoding +/encode_audio +/encode_video +/extract_mvs +/filter_audio +/filtering_audio +/filtering_video +/http_multiclient +/hw_decode +/metadata +/muxing +/pc-uninstalled +/qsvdec +/remuxing +/resampling_audio +/scaling_video +/transcode_aac +/transcoding diff --git a/doc/examples/Makefile b/doc/examples/Makefile index 58afd71b8..da5af3653 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -19,6 +19,7 @@ EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding +EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode EXAMPLES := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)$(EXESUF)) EXAMPLES_G := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)_g$(EXESUF)) diff --git a/doc/examples/avio_reading.c b/doc/examples/avio_reading.c index 02474e907..7860fd5e2 100644 --- a/doc/examples/avio_reading.c +++ b/doc/examples/avio_reading.c @@ -44,6 +44,8 @@ static int read_packet(void *opaque, uint8_t *buf, int buf_size) struct buffer_data *bd = (struct buffer_data *)opaque; buf_size = FFMIN(buf_size, bd->size); + if (!buf_size) + return AVERROR_EOF; printf("ptr:%p size:%zu\n", bd->ptr, bd->size); /* copy internal buffer data to buf */ diff --git a/doc/examples/filter_audio.c b/doc/examples/filter_audio.c index 01761dcee..7467c21c3 100644 --- a/doc/examples/filter_audio.c +++ b/doc/examples/filter_audio.c @@ -64,13 +64,13 @@ static int init_filter_graph(AVFilterGraph **graph, AVFilterContext **src, { AVFilterGraph *filter_graph; AVFilterContext *abuffer_ctx; - AVFilter *abuffer; + const AVFilter *abuffer; AVFilterContext *volume_ctx; - AVFilter *volume; + const AVFilter *volume; AVFilterContext *aformat_ctx; - AVFilter *aformat; + const AVFilter *aformat; AVFilterContext *abuffersink_ctx; - AVFilter *abuffersink; + const AVFilter *abuffersink; AVDictionary *options_dict = NULL; uint8_t options_str[1024]; diff --git a/doc/examples/filtering_audio.c b/doc/examples/filtering_audio.c index 9fc4f1cb7..18d6ca275 100644 --- a/doc/examples/filtering_audio.c +++ b/doc/examples/filtering_audio.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -90,8 +89,8 @@ static int init_filters(const char *filters_descr) { char args[512]; int ret = 0; - AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); - AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); + const AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); + const AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; diff --git a/doc/examples/filtering_video.c b/doc/examples/filtering_video.c index 4e09c6fba..9b607ba01 100644 --- a/doc/examples/filtering_video.c +++ b/doc/examples/filtering_video.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -93,8 +92,8 @@ static int init_filters(const char *filters_descr) { char args[512]; int ret = 0; - AVFilter *buffersrc = avfilter_get_by_name("buffer"); - AVFilter *buffersink = avfilter_get_by_name("buffersink"); + const AVFilter *buffersrc = avfilter_get_by_name("buffer"); + const AVFilter *buffersink = avfilter_get_by_name("buffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base; diff --git a/doc/examples/hw_decode.c b/doc/examples/hw_decode.c index 9c7adbf51..83a5808bf 100644 --- a/doc/examples/hw_decode.c +++ b/doc/examples/hw_decode.c @@ -44,34 +44,6 @@ static AVBufferRef *hw_device_ctx = NULL; static enum AVPixelFormat hw_pix_fmt; static FILE *output_file = NULL; -static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) -{ - enum AVPixelFormat fmt; - - switch (type) { - case AV_HWDEVICE_TYPE_VAAPI: - fmt = AV_PIX_FMT_VAAPI; - break; - case AV_HWDEVICE_TYPE_DXVA2: - fmt = AV_PIX_FMT_DXVA2_VLD; - break; - case AV_HWDEVICE_TYPE_D3D11VA: - fmt = AV_PIX_FMT_D3D11; - break; - case AV_HWDEVICE_TYPE_VDPAU: - fmt = AV_PIX_FMT_VDPAU; - break; - case AV_HWDEVICE_TYPE_VIDEOTOOLBOX: - fmt = AV_PIX_FMT_VIDEOTOOLBOX; - break; - default: - fmt = AV_PIX_FMT_NONE; - break; - } - - return fmt; -} - static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) { int err = 0; @@ -184,18 +156,22 @@ int main(int argc, char *argv[]) AVCodec *decoder = NULL; AVPacket packet; enum AVHWDeviceType type; + int i; if (argc < 4) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s \n", argv[0]); return -1; } av_register_all(); type = av_hwdevice_find_type_by_name(argv[1]); - hw_pix_fmt = find_fmt_by_hw_type(type); - if (hw_pix_fmt == -1) { - fprintf(stderr, "Cannot support '%s' in this example.\n", argv[1]); + if (type == AV_HWDEVICE_TYPE_NONE) { + fprintf(stderr, "Device type %s is not supported.\n", argv[1]); + fprintf(stderr, "Available device types:"); + while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) + fprintf(stderr, " %s", av_hwdevice_get_type_name(type)); + fprintf(stderr, "\n"); return -1; } @@ -218,6 +194,20 @@ int main(int argc, char *argv[]) } video_stream = ret; + for (i = 0;; i++) { + const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i); + if (!config) { + fprintf(stderr, "Decoder %s does not support device type %s.\n", + decoder->name, av_hwdevice_get_type_name(type)); + return -1; + } + if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && + config->device_type == type) { + hw_pix_fmt = config->pix_fmt; + break; + } + } + if (!(decoder_ctx = avcodec_alloc_context3(decoder))) return AVERROR(ENOMEM); diff --git a/doc/examples/muxing.c b/doc/examples/muxing.c index e1a4770eb..6b98a3b2a 100644 --- a/doc/examples/muxing.c +++ b/doc/examples/muxing.c @@ -488,9 +488,9 @@ static AVFrame *get_video_frame(OutputStream *ost) } } fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height); - sws_scale(ost->sws_ctx, - (const uint8_t * const *)ost->tmp_frame->data, ost->tmp_frame->linesize, - 0, c->height, ost->frame->data, ost->frame->linesize); + sws_scale(ost->sws_ctx, (const uint8_t * const *) ost->tmp_frame->data, + ost->tmp_frame->linesize, 0, c->height, ost->frame->data, + ost->frame->linesize); } else { fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height); } diff --git a/doc/examples/transcode_aac.c b/doc/examples/transcode_aac.c index 6c2f4fb47..9fd5c00d6 100644 --- a/doc/examples/transcode_aac.c +++ b/doc/examples/transcode_aac.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2013-2017 Andreas Unterweger + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -8,7 +10,7 @@ * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public @@ -18,10 +20,11 @@ /** * @file - * simple audio converter + * Simple audio converter * * @example transcode_aac.c * Convert an input audio file to AAC in an MP4 container using FFmpeg. + * Formats other than MP4 are supported based on the output file extension. * @author Andreas Unterweger (dustsigns@gmail.com) */ @@ -40,12 +43,18 @@ #include "libswresample/swresample.h" -/** The output bit rate in kbit/s */ +/* The output bit rate in bit/s */ #define OUTPUT_BIT_RATE 96000 -/** The number of output channels */ +/* The number of output channels */ #define OUTPUT_CHANNELS 2 -/** Open an input file and the required decoder. */ +/** + * Open an input file and the required decoder. + * @param filename File to be opened + * @param[out] input_format_context Format context of opened file + * @param[out] input_codec_context Codec context of opened file + * @return Error code (0 if successful) + */ static int open_input_file(const char *filename, AVFormatContext **input_format_context, AVCodecContext **input_codec_context) @@ -54,7 +63,7 @@ static int open_input_file(const char *filename, AVCodec *input_codec; int error; - /** Open the input file to read from it. */ + /* Open the input file to read from it. */ if ((error = avformat_open_input(input_format_context, filename, NULL, NULL)) < 0) { fprintf(stderr, "Could not open input file '%s' (error '%s')\n", @@ -63,7 +72,7 @@ static int open_input_file(const char *filename, return error; } - /** Get information on the input file (number of streams etc.). */ + /* Get information on the input file (number of streams etc.). */ if ((error = avformat_find_stream_info(*input_format_context, NULL)) < 0) { fprintf(stderr, "Could not open find stream info (error '%s')\n", av_err2str(error)); @@ -71,7 +80,7 @@ static int open_input_file(const char *filename, return error; } - /** Make sure that there is only one stream in the input file. */ + /* Make sure that there is only one stream in the input file. */ if ((*input_format_context)->nb_streams != 1) { fprintf(stderr, "Expected one audio input stream, but found %d\n", (*input_format_context)->nb_streams); @@ -79,14 +88,14 @@ static int open_input_file(const char *filename, return AVERROR_EXIT; } - /** Find a decoder for the audio stream. */ + /* Find a decoder for the audio stream. */ if (!(input_codec = avcodec_find_decoder((*input_format_context)->streams[0]->codecpar->codec_id))) { fprintf(stderr, "Could not find input codec\n"); avformat_close_input(input_format_context); return AVERROR_EXIT; } - /** allocate a new decoding context */ + /* Allocate a new decoding context. */ avctx = avcodec_alloc_context3(input_codec); if (!avctx) { fprintf(stderr, "Could not allocate a decoding context\n"); @@ -94,7 +103,7 @@ static int open_input_file(const char *filename, return AVERROR(ENOMEM); } - /** initialize the stream parameters with demuxer information */ + /* Initialize the stream parameters with demuxer information. */ error = avcodec_parameters_to_context(avctx, (*input_format_context)->streams[0]->codecpar); if (error < 0) { avformat_close_input(input_format_context); @@ -102,7 +111,7 @@ static int open_input_file(const char *filename, return error; } - /** Open the decoder for the audio stream to use it later. */ + /* Open the decoder for the audio stream to use it later. */ if ((error = avcodec_open2(avctx, input_codec, NULL)) < 0) { fprintf(stderr, "Could not open input codec (error '%s')\n", av_err2str(error)); @@ -111,7 +120,7 @@ static int open_input_file(const char *filename, return error; } - /** Save the decoder context for easier access later. */ + /* Save the decoder context for easier access later. */ *input_codec_context = avctx; return 0; @@ -121,6 +130,11 @@ static int open_input_file(const char *filename, * Open an output file and the required encoder. * Also set some basic encoder parameters. * Some of these parameters are based on the input file's parameters. + * @param filename File to be opened + * @param input_codec_context Codec context of input file + * @param[out] output_format_context Format context of output file + * @param[out] output_codec_context Codec context of output file + * @return Error code (0 if successful) */ static int open_output_file(const char *filename, AVCodecContext *input_codec_context, @@ -133,7 +147,7 @@ static int open_output_file(const char *filename, AVCodec *output_codec = NULL; int error; - /** Open the output file to write to it. */ + /* Open the output file to write to it. */ if ((error = avio_open(&output_io_context, filename, AVIO_FLAG_WRITE)) < 0) { fprintf(stderr, "Could not open output file '%s' (error '%s')\n", @@ -141,16 +155,16 @@ static int open_output_file(const char *filename, return error; } - /** Create a new format context for the output container format. */ + /* Create a new format context for the output container format. */ if (!(*output_format_context = avformat_alloc_context())) { fprintf(stderr, "Could not allocate output format context\n"); return AVERROR(ENOMEM); } - /** Associate the output file (pointer) with the container format context. */ + /* Associate the output file (pointer) with the container format context. */ (*output_format_context)->pb = output_io_context; - /** Guess the desired container format based on the file extension. */ + /* Guess the desired container format based on the file extension. */ if (!((*output_format_context)->oformat = av_guess_format(NULL, filename, NULL))) { fprintf(stderr, "Could not find output file format\n"); @@ -160,13 +174,13 @@ static int open_output_file(const char *filename, av_strlcpy((*output_format_context)->filename, filename, sizeof((*output_format_context)->filename)); - /** Find the encoder to be used by its name. */ + /* Find the encoder to be used by its name. */ if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC))) { fprintf(stderr, "Could not find an AAC encoder.\n"); goto cleanup; } - /** Create a new audio stream in the output file container. */ + /* Create a new audio stream in the output file container. */ if (!(stream = avformat_new_stream(*output_format_context, NULL))) { fprintf(stderr, "Could not create new stream\n"); error = AVERROR(ENOMEM); @@ -180,31 +194,27 @@ static int open_output_file(const char *filename, goto cleanup; } - /** - * Set the basic encoder parameters. - * The input file's sample rate is used to avoid a sample rate conversion. - */ + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ avctx->channels = OUTPUT_CHANNELS; avctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS); avctx->sample_rate = input_codec_context->sample_rate; avctx->sample_fmt = output_codec->sample_fmts[0]; avctx->bit_rate = OUTPUT_BIT_RATE; - /** Allow the use of the experimental AAC encoder */ + /* Allow the use of the experimental AAC encoder. */ avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; - /** Set the sample rate for the container. */ + /* Set the sample rate for the container. */ stream->time_base.den = input_codec_context->sample_rate; stream->time_base.num = 1; - /** - * Some container formats (like MP4) require global headers to be present - * Mark the encoder so that it behaves accordingly. - */ + /* Some container formats (like MP4) require global headers to be present. + * Mark the encoder so that it behaves accordingly. */ if ((*output_format_context)->oformat->flags & AVFMT_GLOBALHEADER) avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - /** Open the encoder for the audio stream to use it later. */ + /* Open the encoder for the audio stream to use it later. */ if ((error = avcodec_open2(avctx, output_codec, NULL)) < 0) { fprintf(stderr, "Could not open output codec (error '%s')\n", av_err2str(error)); @@ -217,7 +227,7 @@ static int open_output_file(const char *filename, goto cleanup; } - /** Save the encoder context for easier access later. */ + /* Save the encoder context for easier access later. */ *output_codec_context = avctx; return 0; @@ -230,16 +240,23 @@ cleanup: return error < 0 ? error : AVERROR_EXIT; } -/** Initialize one data packet for reading or writing. */ +/** + * Initialize one data packet for reading or writing. + * @param packet Packet to be initialized + */ static void init_packet(AVPacket *packet) { av_init_packet(packet); - /** Set the packet data and size so that it is recognized as being empty. */ + /* Set the packet data and size so that it is recognized as being empty. */ packet->data = NULL; packet->size = 0; } -/** Initialize one audio frame for reading from the input file */ +/** + * Initialize one audio frame for reading from the input file. + * @param[out] frame Frame to be initialized + * @return Error code (0 if successful) + */ static int init_input_frame(AVFrame **frame) { if (!(*frame = av_frame_alloc())) { @@ -253,6 +270,10 @@ static int init_input_frame(AVFrame **frame) * Initialize the audio resampler based on the input and output codec settings. * If the input and output sample formats differ, a conversion is required * libswresample takes care of this, but requires initialization. + * @param input_codec_context Codec context of the input file + * @param output_codec_context Codec context of the output file + * @param[out] resample_context Resample context for the required conversion + * @return Error code (0 if successful) */ static int init_resampler(AVCodecContext *input_codec_context, AVCodecContext *output_codec_context, @@ -260,7 +281,7 @@ static int init_resampler(AVCodecContext *input_codec_context, { int error; - /** + /* * Create a resampler context for the conversion. * Set the conversion parameters. * Default channel layouts based on the number of channels @@ -279,14 +300,14 @@ static int init_resampler(AVCodecContext *input_codec_context, fprintf(stderr, "Could not allocate resample context\n"); return AVERROR(ENOMEM); } - /** + /* * Perform a sanity check so that the number of converted samples is * not greater than the number of samples to be converted. * If the sample rates differ, this case has to be handled differently */ av_assert0(output_codec_context->sample_rate == input_codec_context->sample_rate); - /** Open the resampler with the specified parameters. */ + /* Open the resampler with the specified parameters. */ if ((error = swr_init(*resample_context)) < 0) { fprintf(stderr, "Could not open resample context\n"); swr_free(resample_context); @@ -295,10 +316,15 @@ static int init_resampler(AVCodecContext *input_codec_context, return 0; } -/** Initialize a FIFO buffer for the audio samples to be encoded. */ +/** + * Initialize a FIFO buffer for the audio samples to be encoded. + * @param[out] fifo Sample buffer + * @param output_codec_context Codec context of the output file + * @return Error code (0 if successful) + */ static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context) { - /** Create the FIFO buffer based on the specified output sample format. */ + /* Create the FIFO buffer based on the specified output sample format. */ if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt, output_codec_context->channels, 1))) { fprintf(stderr, "Could not allocate FIFO\n"); @@ -307,7 +333,11 @@ static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context) return 0; } -/** Write the header of the output file container. */ +/** + * Write the header of the output file container. + * @param output_format_context Format context of the output file + * @return Error code (0 if successful) + */ static int write_output_file_header(AVFormatContext *output_format_context) { int error; @@ -319,20 +349,32 @@ static int write_output_file_header(AVFormatContext *output_format_context) return 0; } -/** Decode one audio frame from the input file. */ +/** + * Decode one audio frame from the input file. + * @param frame Audio frame to be decoded + * @param input_format_context Format context of the input file + * @param input_codec_context Codec context of the input file + * @param[out] data_present Indicates whether data has been decoded + * @param[out] finished Indicates whether the end of file has + * been reached and all data has been + * decoded. If this flag is false, there + * is more data to be decoded, i.e., this + * function has to be called again. + * @return Error code (0 if successful) + */ static int decode_audio_frame(AVFrame *frame, AVFormatContext *input_format_context, AVCodecContext *input_codec_context, int *data_present, int *finished) { - /** Packet used for temporary storage. */ + /* Packet used for temporary storage. */ AVPacket input_packet; int error; init_packet(&input_packet); - /** Read one audio frame from the input file into a temporary packet. */ + /* Read one audio frame from the input file into a temporary packet. */ if ((error = av_read_frame(input_format_context, &input_packet)) < 0) { - /** If we are at the end of the file, flush the decoder below. */ + /* If we are at the end of the file, flush the decoder below. */ if (error == AVERROR_EOF) *finished = 1; else { @@ -342,12 +384,10 @@ static int decode_audio_frame(AVFrame *frame, } } - /** - * Decode the audio frame stored in the temporary packet. + /* Decode the audio frame stored in the temporary packet. * The input audio stream decoder is used to do this. * If we are at the end of the file, pass an empty packet to the decoder - * to flush it. - */ + * to flush it. */ if ((error = avcodec_decode_audio4(input_codec_context, frame, data_present, &input_packet)) < 0) { fprintf(stderr, "Could not decode frame (error '%s')\n", @@ -356,10 +396,8 @@ static int decode_audio_frame(AVFrame *frame, return error; } - /** - * If the decoder has not been flushed completely, we are not finished, - * so that this function has to be called again. - */ + /* If the decoder has not been flushed completely, we are not finished, + * so that this function has to be called again. */ if (*finished && *data_present) *finished = 0; av_packet_unref(&input_packet); @@ -370,6 +408,13 @@ static int decode_audio_frame(AVFrame *frame, * Initialize a temporary storage for the specified number of audio samples. * The conversion requires temporary storage due to the different format. * The number of audio samples to be allocated is specified in frame_size. + * @param[out] converted_input_samples Array of converted samples. The + * dimensions are reference, channel + * (for multi-channel audio), sample. + * @param output_codec_context Codec context of the output file + * @param frame_size Number of samples to be converted in + * each round + * @return Error code (0 if successful) */ static int init_converted_samples(uint8_t ***converted_input_samples, AVCodecContext *output_codec_context, @@ -377,8 +422,7 @@ static int init_converted_samples(uint8_t ***converted_input_samples, { int error; - /** - * Allocate as many pointers as there are audio channels. + /* Allocate as many pointers as there are audio channels. * Each pointer will later point to the audio samples of the corresponding * channels (although it may be NULL for interleaved formats). */ @@ -388,10 +432,8 @@ static int init_converted_samples(uint8_t ***converted_input_samples, return AVERROR(ENOMEM); } - /** - * Allocate memory for the samples of all channels in one consecutive - * block for convenience. - */ + /* Allocate memory for the samples of all channels in one consecutive + * block for convenience. */ if ((error = av_samples_alloc(*converted_input_samples, NULL, output_codec_context->channels, frame_size, @@ -408,8 +450,15 @@ static int init_converted_samples(uint8_t ***converted_input_samples, /** * Convert the input audio samples into the output sample format. - * The conversion happens on a per-frame basis, the size of which is specified - * by frame_size. + * The conversion happens on a per-frame basis, the size of which is + * specified by frame_size. + * @param input_data Samples to be decoded. The dimensions are + * channel (for multi-channel audio), sample. + * @param[out] converted_data Converted samples. The dimensions are channel + * (for multi-channel audio), sample. + * @param frame_size Number of samples to be converted + * @param resample_context Resample context for the conversion + * @return Error code (0 if successful) */ static int convert_samples(const uint8_t **input_data, uint8_t **converted_data, const int frame_size, @@ -417,7 +466,7 @@ static int convert_samples(const uint8_t **input_data, { int error; - /** Convert the samples using the resampler. */ + /* Convert the samples using the resampler. */ if ((error = swr_convert(resample_context, converted_data, frame_size, input_data , frame_size)) < 0) { @@ -429,23 +478,28 @@ static int convert_samples(const uint8_t **input_data, return 0; } -/** Add converted input audio samples to the FIFO buffer for later processing. */ +/** + * Add converted input audio samples to the FIFO buffer for later processing. + * @param fifo Buffer to add the samples to + * @param converted_input_samples Samples to be added. The dimensions are channel + * (for multi-channel audio), sample. + * @param frame_size Number of samples to be converted + * @return Error code (0 if successful) + */ static int add_samples_to_fifo(AVAudioFifo *fifo, uint8_t **converted_input_samples, const int frame_size) { int error; - /** - * Make the FIFO as large as it needs to be to hold both, - * the old and the new samples. - */ + /* Make the FIFO as large as it needs to be to hold both, + * the old and the new samples. */ if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) { fprintf(stderr, "Could not reallocate FIFO\n"); return error; } - /** Store the new samples in the FIFO buffer. */ + /* Store the new samples in the FIFO buffer. */ if (av_audio_fifo_write(fifo, (void **)converted_input_samples, frame_size) < frame_size) { fprintf(stderr, "Could not write data to FIFO\n"); @@ -455,8 +509,20 @@ static int add_samples_to_fifo(AVAudioFifo *fifo, } /** - * Read one audio frame from the input file, decodes, converts and stores + * Read one audio frame from the input file, decode, convert and store * it in the FIFO buffer. + * @param fifo Buffer used for temporary storage + * @param input_format_context Format context of the input file + * @param input_codec_context Codec context of the input file + * @param output_codec_context Codec context of the output file + * @param resampler_context Resample context for the conversion + * @param[out] finished Indicates whether the end of file has + * been reached and all data has been + * decoded. If this flag is false, + * there is more data to be decoded, + * i.e., this function has to be called + * again. + * @return Error code (0 if successful) */ static int read_decode_convert_and_store(AVAudioFifo *fifo, AVFormatContext *input_format_context, @@ -465,45 +531,41 @@ static int read_decode_convert_and_store(AVAudioFifo *fifo, SwrContext *resampler_context, int *finished) { - /** Temporary storage of the input samples of the frame read from the file. */ + /* Temporary storage of the input samples of the frame read from the file. */ AVFrame *input_frame = NULL; - /** Temporary storage for the converted input samples. */ + /* Temporary storage for the converted input samples. */ uint8_t **converted_input_samples = NULL; int data_present; int ret = AVERROR_EXIT; - /** Initialize temporary storage for one input frame. */ + /* Initialize temporary storage for one input frame. */ if (init_input_frame(&input_frame)) goto cleanup; - /** Decode one frame worth of audio samples. */ + /* Decode one frame worth of audio samples. */ if (decode_audio_frame(input_frame, input_format_context, input_codec_context, &data_present, finished)) goto cleanup; - /** - * If we are at the end of the file and there are no more samples + /* If we are at the end of the file and there are no more samples * in the decoder which are delayed, we are actually finished. - * This must not be treated as an error. - */ + * This must not be treated as an error. */ if (*finished && !data_present) { ret = 0; goto cleanup; } - /** If there is decoded data, convert and store it */ + /* If there is decoded data, convert and store it. */ if (data_present) { - /** Initialize the temporary storage for the converted input samples. */ + /* Initialize the temporary storage for the converted input samples. */ if (init_converted_samples(&converted_input_samples, output_codec_context, input_frame->nb_samples)) goto cleanup; - /** - * Convert the input samples to the desired output sample format. - * This requires a temporary storage provided by converted_input_samples. - */ + /* Convert the input samples to the desired output sample format. + * This requires a temporary storage provided by converted_input_samples. */ if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples, input_frame->nb_samples, resampler_context)) goto cleanup; - /** Add the converted input samples to the FIFO buffer for later processing. */ + /* Add the converted input samples to the FIFO buffer for later processing. */ if (add_samples_to_fifo(fifo, converted_input_samples, input_frame->nb_samples)) goto cleanup; @@ -524,6 +586,10 @@ cleanup: /** * Initialize one input frame for writing to the output file. * The frame will be exactly frame_size samples large. + * @param[out] frame Frame to be initialized + * @param output_codec_context Codec context of the output file + * @param frame_size Size of the frame + * @return Error code (0 if successful) */ static int init_output_frame(AVFrame **frame, AVCodecContext *output_codec_context, @@ -531,28 +597,24 @@ static int init_output_frame(AVFrame **frame, { int error; - /** Create a new frame to store the audio samples. */ + /* Create a new frame to store the audio samples. */ if (!(*frame = av_frame_alloc())) { fprintf(stderr, "Could not allocate output frame\n"); return AVERROR_EXIT; } - /** - * Set the frame's parameters, especially its size and format. + /* Set the frame's parameters, especially its size and format. * av_frame_get_buffer needs this to allocate memory for the * audio samples of the frame. * Default channel layouts based on the number of channels - * are assumed for simplicity. - */ + * are assumed for simplicity. */ (*frame)->nb_samples = frame_size; (*frame)->channel_layout = output_codec_context->channel_layout; (*frame)->format = output_codec_context->sample_fmt; (*frame)->sample_rate = output_codec_context->sample_rate; - /** - * Allocate the samples of the created frame. This call will make - * sure that the audio frame can hold as many samples as specified. - */ + /* Allocate the samples of the created frame. This call will make + * sure that the audio frame can hold as many samples as specified. */ if ((error = av_frame_get_buffer(*frame, 0)) < 0) { fprintf(stderr, "Could not allocate output frame samples (error '%s')\n", av_err2str(error)); @@ -563,30 +625,36 @@ static int init_output_frame(AVFrame **frame, return 0; } -/** Global timestamp for the audio frames */ +/* Global timestamp for the audio frames. */ static int64_t pts = 0; -/** Encode one frame worth of audio to the output file. */ +/** + * Encode one frame worth of audio to the output file. + * @param frame Samples to be encoded + * @param output_format_context Format context of the output file + * @param output_codec_context Codec context of the output file + * @param[out] data_present Indicates whether data has been + * decoded + * @return Error code (0 if successful) + */ static int encode_audio_frame(AVFrame *frame, AVFormatContext *output_format_context, AVCodecContext *output_codec_context, int *data_present) { - /** Packet used for temporary storage. */ + /* Packet used for temporary storage. */ AVPacket output_packet; int error; init_packet(&output_packet); - /** Set a timestamp based on the sample rate for the container. */ + /* Set a timestamp based on the sample rate for the container. */ if (frame) { frame->pts = pts; pts += frame->nb_samples; } - /** - * Encode the audio frame and store it in the temporary packet. - * The output audio stream encoder is used to do this. - */ + /* Encode the audio frame and store it in the temporary packet. + * The output audio stream encoder is used to do this. */ if ((error = avcodec_encode_audio2(output_codec_context, &output_packet, frame, data_present)) < 0) { fprintf(stderr, "Could not encode frame (error '%s')\n", @@ -595,7 +663,7 @@ static int encode_audio_frame(AVFrame *frame, return error; } - /** Write one audio frame from the temporary packet to the output file. */ + /* Write one audio frame from the temporary packet to the output file. */ if (*data_present) { if ((error = av_write_frame(output_format_context, &output_packet)) < 0) { fprintf(stderr, "Could not write frame (error '%s')\n", @@ -613,37 +681,37 @@ static int encode_audio_frame(AVFrame *frame, /** * Load one audio frame from the FIFO buffer, encode and write it to the * output file. + * @param fifo Buffer used for temporary storage + * @param output_format_context Format context of the output file + * @param output_codec_context Codec context of the output file + * @return Error code (0 if successful) */ static int load_encode_and_write(AVAudioFifo *fifo, AVFormatContext *output_format_context, AVCodecContext *output_codec_context) { - /** Temporary storage of the output samples of the frame written to the file. */ + /* Temporary storage of the output samples of the frame written to the file. */ AVFrame *output_frame; - /** - * Use the maximum number of possible samples per frame. + /* Use the maximum number of possible samples per frame. * If there is less than the maximum possible frame size in the FIFO - * buffer use this number. Otherwise, use the maximum possible frame size - */ + * buffer use this number. Otherwise, use the maximum possible frame size. */ const int frame_size = FFMIN(av_audio_fifo_size(fifo), output_codec_context->frame_size); int data_written; - /** Initialize temporary storage for one output frame. */ + /* Initialize temporary storage for one output frame. */ if (init_output_frame(&output_frame, output_codec_context, frame_size)) return AVERROR_EXIT; - /** - * Read as many samples from the FIFO buffer as required to fill the frame. - * The samples are stored in the frame temporarily. - */ + /* Read as many samples from the FIFO buffer as required to fill the frame. + * The samples are stored in the frame temporarily. */ if (av_audio_fifo_read(fifo, (void **)output_frame->data, frame_size) < frame_size) { fprintf(stderr, "Could not read data from FIFO\n"); av_frame_free(&output_frame); return AVERROR_EXIT; } - /** Encode one frame worth of audio samples. */ + /* Encode one frame worth of audio samples. */ if (encode_audio_frame(output_frame, output_format_context, output_codec_context, &data_written)) { av_frame_free(&output_frame); @@ -653,7 +721,11 @@ static int load_encode_and_write(AVAudioFifo *fifo, return 0; } -/** Write the trailer of the output file container. */ +/** + * Write the trailer of the output file container. + * @param output_format_context Format context of the output file + * @return Error code (0 if successful) + */ static int write_output_file_trailer(AVFormatContext *output_format_context) { int error; @@ -665,7 +737,6 @@ static int write_output_file_trailer(AVFormatContext *output_format_context) return 0; } -/** Convert an audio file to an AAC file in an MP4 container. */ int main(int argc, char **argv) { AVFormatContext *input_format_context = NULL, *output_format_context = NULL; @@ -674,89 +745,75 @@ int main(int argc, char **argv) AVAudioFifo *fifo = NULL; int ret = AVERROR_EXIT; - if (argc < 3) { + if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } - /** Register all codecs and formats so that they can be used. */ + /* Register all codecs and formats so that they can be used. */ av_register_all(); - /** Open the input file for reading. */ + /* Open the input file for reading. */ if (open_input_file(argv[1], &input_format_context, &input_codec_context)) goto cleanup; - /** Open the output file for writing. */ + /* Open the output file for writing. */ if (open_output_file(argv[2], input_codec_context, &output_format_context, &output_codec_context)) goto cleanup; - /** Initialize the resampler to be able to convert audio sample formats. */ + /* Initialize the resampler to be able to convert audio sample formats. */ if (init_resampler(input_codec_context, output_codec_context, &resample_context)) goto cleanup; - /** Initialize the FIFO buffer to store audio samples to be encoded. */ + /* Initialize the FIFO buffer to store audio samples to be encoded. */ if (init_fifo(&fifo, output_codec_context)) goto cleanup; - /** Write the header of the output file container. */ + /* Write the header of the output file container. */ if (write_output_file_header(output_format_context)) goto cleanup; - /** - * Loop as long as we have input samples to read or output samples - * to write; abort as soon as we have neither. - */ + /* Loop as long as we have input samples to read or output samples + * to write; abort as soon as we have neither. */ while (1) { - /** Use the encoder's desired frame size for processing. */ + /* Use the encoder's desired frame size for processing. */ const int output_frame_size = output_codec_context->frame_size; int finished = 0; - /** - * Make sure that there is one frame worth of samples in the FIFO + /* Make sure that there is one frame worth of samples in the FIFO * buffer so that the encoder can do its work. * Since the decoder's and the encoder's frame size may differ, we * need to FIFO buffer to store as many frames worth of input samples - * that they make up at least one frame worth of output samples. - */ + * that they make up at least one frame worth of output samples. */ while (av_audio_fifo_size(fifo) < output_frame_size) { - /** - * Decode one frame worth of audio samples, convert it to the - * output sample format and put it into the FIFO buffer. - */ + /* Decode one frame worth of audio samples, convert it to the + * output sample format and put it into the FIFO buffer. */ if (read_decode_convert_and_store(fifo, input_format_context, input_codec_context, output_codec_context, resample_context, &finished)) goto cleanup; - /** - * If we are at the end of the input file, we continue - * encoding the remaining audio samples to the output file. - */ + /* If we are at the end of the input file, we continue + * encoding the remaining audio samples to the output file. */ if (finished) break; } - /** - * If we have enough samples for the encoder, we encode them. + /* If we have enough samples for the encoder, we encode them. * At the end of the file, we pass the remaining samples to - * the encoder. - */ + * the encoder. */ while (av_audio_fifo_size(fifo) >= output_frame_size || (finished && av_audio_fifo_size(fifo) > 0)) - /** - * Take one frame worth of audio samples from the FIFO buffer, - * encode it and write it to the output file. - */ + /* Take one frame worth of audio samples from the FIFO buffer, + * encode it and write it to the output file. */ if (load_encode_and_write(fifo, output_format_context, output_codec_context)) goto cleanup; - /** - * If we are at the end of the input file and have encoded - * all remaining samples, we can exit this loop and finish. - */ + /* If we are at the end of the input file and have encoded + * all remaining samples, we can exit this loop and finish. */ if (finished) { int data_written; - /** Flush the encoder as it may have delayed frames. */ + /* Flush the encoder as it may have delayed frames. */ do { if (encode_audio_frame(NULL, output_format_context, output_codec_context, &data_written)) @@ -766,7 +823,7 @@ int main(int argc, char **argv) } } - /** Write the trailer of the output file container. */ + /* Write the trailer of the output file container. */ if (write_output_file_trailer(output_format_context)) goto cleanup; ret = 0; diff --git a/doc/examples/transcoding.c b/doc/examples/transcoding.c index fb15a2148..e32ab2024 100644 --- a/doc/examples/transcoding.c +++ b/doc/examples/transcoding.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -228,8 +227,8 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, { char args[512]; int ret = 0; - AVFilter *buffersrc = NULL; - AVFilter *buffersink = NULL; + const AVFilter *buffersrc = NULL; + const AVFilter *buffersink = NULL; AVFilterContext *buffersrc_ctx = NULL; AVFilterContext *buffersink_ctx = NULL; AVFilterInOut *outputs = avfilter_inout_alloc(); diff --git a/doc/examples/vaapi_encode.c b/doc/examples/vaapi_encode.c new file mode 100644 index 000000000..6425b1c98 --- /dev/null +++ b/doc/examples/vaapi_encode.c @@ -0,0 +1,224 @@ +/* + * Video Acceleration API (video encoding) encode sample + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * Intel VAAPI-accelerated encoding example. + * + * @example vaapi_encode.c + * This example shows how to do VAAPI-accelerated encoding. now only support NV12 + * raw file, usage like: vaapi_encode 1920 1080 input.yuv output.h264 + * + */ + +#include +#include +#include + +#include +#include +#include + +static int width, height; +static AVBufferRef *hw_device_ctx = NULL; + +static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx) +{ + AVBufferRef *hw_frames_ref; + AVHWFramesContext *frames_ctx = NULL; + int err = 0; + + if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { + fprintf(stderr, "Failed to create VAAPI frame context.\n"); + return -1; + } + frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + frames_ctx->format = AV_PIX_FMT_VAAPI; + frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->width = width; + frames_ctx->height = height; + frames_ctx->initial_pool_size = 20; + if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { + fprintf(stderr, "Failed to initialize VAAPI frame context." + "Error code: %s\n",av_err2str(err)); + av_buffer_unref(&hw_frames_ref); + return err; + } + ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref); + if (!ctx->hw_frames_ctx) + err = AVERROR(ENOMEM); + + av_buffer_unref(&hw_frames_ref); + return err; +} + +static int encode_write(AVCodecContext *avctx, AVFrame *frame, FILE *fout) +{ + int ret = 0; + AVPacket enc_pkt; + + av_init_packet(&enc_pkt); + enc_pkt.data = NULL; + enc_pkt.size = 0; + + if ((ret = avcodec_send_frame(avctx, frame)) < 0) { + fprintf(stderr, "Error code: %s\n", av_err2str(ret)); + goto end; + } + while (1) { + ret = avcodec_receive_packet(avctx, &enc_pkt); + if (ret) + break; + + enc_pkt.stream_index = 0; + ret = fwrite(enc_pkt.data, enc_pkt.size, 1, fout); + av_packet_unref(&enc_pkt); + } + +end: + ret = ((ret == AVERROR(EAGAIN)) ? 0 : -1); + return ret; +} + +int main(int argc, char *argv[]) +{ + int size, err; + FILE *fin = NULL, *fout = NULL; + AVFrame *sw_frame = NULL, *hw_frame = NULL; + AVCodecContext *avctx = NULL; + AVCodec *codec = NULL; + const char *enc_name = "h264_vaapi"; + + if (argc < 5) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + width = atoi(argv[1]); + height = atoi(argv[2]); + size = width * height; + + if (!(fin = fopen(argv[3], "r"))) { + fprintf(stderr, "Fail to open input file : %s\n", strerror(errno)); + return -1; + } + if (!(fout = fopen(argv[4], "w+b"))) { + fprintf(stderr, "Fail to open output file : %s\n", strerror(errno)); + err = -1; + goto close; + } + + avcodec_register_all(); + + err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, + NULL, NULL, 0); + if (err < 0) { + fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", av_err2str(err)); + goto close; + } + + if (!(codec = avcodec_find_encoder_by_name(enc_name))) { + fprintf(stderr, "Could not find encoder.\n"); + err = -1; + goto close; + } + + if (!(avctx = avcodec_alloc_context3(codec))) { + err = AVERROR(ENOMEM); + goto close; + } + + avctx->width = width; + avctx->height = height; + avctx->time_base = (AVRational){1, 25}; + avctx->framerate = (AVRational){25, 1}; + avctx->sample_aspect_ratio = (AVRational){1, 1}; + avctx->pix_fmt = AV_PIX_FMT_VAAPI; + + /* set hw_frames_ctx for encoder's AVCodecContext */ + if ((err = set_hwframe_ctx(avctx, hw_device_ctx)) < 0) { + fprintf(stderr, "Failed to set hwframe context.\n"); + goto close; + } + + if ((err = avcodec_open2(avctx, codec, NULL)) < 0) { + fprintf(stderr, "Cannot open video encoder codec. Error code: %s\n", av_err2str(err)); + goto close; + } + + while (1) { + if (!(sw_frame = av_frame_alloc())) { + err = AVERROR(ENOMEM); + goto close; + } + /* read data into software frame, and transfer them into hw frame */ + sw_frame->width = width; + sw_frame->height = height; + sw_frame->format = AV_PIX_FMT_NV12; + if ((err = av_frame_get_buffer(sw_frame, 32)) < 0) + goto close; + if ((err = fread((uint8_t*)(sw_frame->data[0]), size, 1, fin)) <= 0) + break; + if ((err = fread((uint8_t*)(sw_frame->data[1]), size/2, 1, fin)) <= 0) + break; + + if (!(hw_frame = av_frame_alloc())) { + err = AVERROR(ENOMEM); + goto close; + } + if ((err = av_hwframe_get_buffer(avctx->hw_frames_ctx, hw_frame, 0)) < 0) { + fprintf(stderr, "Error code: %s.\n", av_err2str(err)); + goto close; + } + if (!hw_frame->hw_frames_ctx) { + err = AVERROR(ENOMEM); + goto close; + } + if ((err = av_hwframe_transfer_data(hw_frame, sw_frame, 0)) < 0) { + fprintf(stderr, "Error while transferring frame data to surface." + "Error code: %s.\n", av_err2str(err)); + goto close; + } + + if ((err = (encode_write(avctx, hw_frame, fout))) < 0) { + fprintf(stderr, "Failed to encode.\n"); + goto close; + } + av_frame_free(&hw_frame); + av_frame_free(&sw_frame); + } + + /* flush encoder */ + err = encode_write(avctx, NULL, fout); + if (err == AVERROR_EOF) + err = 0; + +close: + if (fin) + fclose(fin); + if (fout) + fclose(fout); + av_frame_free(&sw_frame); + av_frame_free(&hw_frame); + avcodec_free_context(&avctx); + av_buffer_unref(&hw_device_ctx); + + return err; +} diff --git a/doc/faq.texi b/doc/faq.texi index dcaf89c6d..73624c647 100644 --- a/doc/faq.texi +++ b/doc/faq.texi @@ -501,6 +501,71 @@ ffmpeg -i ega_screen.nut -vf setdar=4/3 ega_screen_anamorphic.nut ffmpeg -i ega_screen.nut -aspect 4/3 -c copy ega_screen_overridden.nut @end example +@anchor{background task} +@section How do I run ffmpeg as a background task? + +ffmpeg normally checks the console input, for entries like "q" to stop +and "?" to give help, while performing operations. ffmpeg does not have a way of +detecting when it is running as a background task. +When it checks the console input, that can cause the process running ffmpeg +in the background to suspend. + +To prevent those input checks, allowing ffmpeg to run as a background task, +use the @url{ffmpeg.html#stdin-option, @code{-nostdin} option} +in the ffmpeg invocation. This is effective whether you run ffmpeg in a shell +or invoke ffmpeg in its own process via an operating system API. + +As an alternative, when you are running ffmpeg in a shell, you can redirect +standard input to @code{/dev/null} (on Linux and Mac OS) +or @code{NUL} (on Windows). You can do this redirect either +on the ffmpeg invocation, or from a shell script which calls ffmpeg. + +For example: + +@example +ffmpeg -nostdin -i INPUT OUTPUT +@end example + +or (on Linux, Mac OS, and other UNIX-like shells): + +@example +ffmpeg -i INPUT OUTPUT ~/tmp/log.txt & +[1] 93352 +% +[1] + suspended (tty output) ffmpeg -i INPUT OUTPUT &> +@end example + +The message "tty output" notwithstanding, the problem here is that +ffmpeg normally checks the console input when it runs. The operating system +detects this, and suspends the process until you can bring it to the +foreground and attend to it. + +The solution is to use the right techniques to tell ffmpeg not to consult +console input. You can use the +@url{ffmpeg.html#stdin-option, @code{-nostdin} option}, +or redirect standard input with @code{< /dev/null}. +See FAQ +@ref{background task, @emph{How do I run ffmpeg as a background task?}} +for details. + @chapter Development @section Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat? diff --git a/doc/fate.texi b/doc/fate.texi index 7a96c25c7..c9c0d3aea 100644 --- a/doc/fate.texi +++ b/doc/fate.texi @@ -147,6 +147,26 @@ process. The only thing left is to automate the execution of the fate.sh script and the synchronisation of the samples directory. +@chapter Uploading new samples to the fate suite + +This is for developers who have an account on the fate suite server. +If you upload new samples, please make sure they are as small as possible, +space on each client, network bandwidth and so on benefit from smaller test cases. +Also keep in mind older checkouts use existing sample files, that means in +practice generally do not replace, remove or overwrite files as it likely would +break older checkouts or releases. + +@example +#First update your local samples copy: +rsync -vauL --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X fate-suite.ffmpeg.org:/home/samples/fate-suite/ ~/fate-suite + +#Then do a dry run checking what would be uploaded: +rsync -vanL --no-g --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X ~/fate-suite/ fate-suite.ffmpeg.org:/home/samples/fate-suite + +#Upload the files: +rsync -vaL --no-g --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X ~/fate-suite/ fate-suite.ffmpeg.org:/home/samples/fate-suite +@end example + @chapter FATE makefile targets and variables diff --git a/doc/ffmpeg-bitstream-filters.texi b/doc/ffmpeg-bitstream-filters.texi index bbde25708..63c0b33a3 100644 --- a/doc/ffmpeg-bitstream-filters.texi +++ b/doc/ffmpeg-bitstream-filters.texi @@ -26,12 +26,12 @@ bitstream level modifications without performing decoding. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavcodec.html,libavcodec} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavcodec(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-codecs.texi b/doc/ffmpeg-codecs.texi index 7df4391ae..e46cd3aeb 100644 --- a/doc/ffmpeg-codecs.texi +++ b/doc/ffmpeg-codecs.texi @@ -23,12 +23,12 @@ the libavcodec library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavcodec.html,libavcodec} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavcodec(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-devices.texi b/doc/ffmpeg-devices.texi index 721c0df80..a51de0014 100644 --- a/doc/ffmpeg-devices.texi +++ b/doc/ffmpeg-devices.texi @@ -23,12 +23,12 @@ libavdevice library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavdevice.html,libavdevice} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavdevice(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavdevice(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-filters.texi b/doc/ffmpeg-filters.texi index b643f2c02..a8ababa9c 100644 --- a/doc/ffmpeg-filters.texi +++ b/doc/ffmpeg-filters.texi @@ -23,12 +23,12 @@ libavfilter library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavfilter.html,libavfilter} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavfilter(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavfilter(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-formats.texi b/doc/ffmpeg-formats.texi index d916ee84b..a1917a726 100644 --- a/doc/ffmpeg-formats.texi +++ b/doc/ffmpeg-formats.texi @@ -23,12 +23,12 @@ provided by the libavformat library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavformat.html,libavformat} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavformat(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-protocols.texi b/doc/ffmpeg-protocols.texi index f3a09f6a6..7f0e62ac6 100644 --- a/doc/ffmpeg-protocols.texi +++ b/doc/ffmpeg-protocols.texi @@ -23,12 +23,12 @@ libavformat library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavformat.html,libavformat} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavformat(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-resampler.texi b/doc/ffmpeg-resampler.texi index be3784f3e..0e9a3dd95 100644 --- a/doc/ffmpeg-resampler.texi +++ b/doc/ffmpeg-resampler.texi @@ -25,12 +25,12 @@ and convert audio format and packing layout. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libswresample.html,libswresample} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libswresample(3) +ffmpeg(1), ffplay(1), ffprobe(1), libswresample(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-scaler.texi b/doc/ffmpeg-scaler.texi index 9ab12a1f9..d259da903 100644 --- a/doc/ffmpeg-scaler.texi +++ b/doc/ffmpeg-scaler.texi @@ -24,12 +24,12 @@ image rescaling and pixel format conversion. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libswscale.html,libswscale} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libswscale(3) +ffmpeg(1), ffplay(1), ffprobe(1), libswscale(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-utils.texi b/doc/ffmpeg-utils.texi index e39cfa85e..d8e08841e 100644 --- a/doc/ffmpeg-utils.texi +++ b/doc/ffmpeg-utils.texi @@ -23,12 +23,12 @@ by the libavutil library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavutil(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavutil(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 0405d009b..25a0707dc 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -289,8 +289,8 @@ see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) -to and -t are mutually exclusive and -t has priority. -@item -to @var{position} (@emph{output}) -Stop writing the output at @var{position}. +@item -to @var{position} (@emph{input/output}) +Stop writing the output or reading the input at @var{position}. @var{position} must be a time duration specification, see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}. @@ -470,6 +470,7 @@ the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key} consists of only alphanumeric characters. The last key of a sequence of progress information is always "progress". +@anchor{stdin option} @item -stdin Enable interaction on standard input. On by default unless standard input is used as an input. To explicitly disable interaction you need to specify @@ -756,6 +757,43 @@ If not specified, @samp{auto_any} is used. platform-appropriate subdevice (@samp{dxva2} or @samp{vaapi}) and then deriving a QSV device from that.) +@item opencl +@var{device} selects the platform and device as @emph{platform_index.device_index}. + +The set of devices can also be filtered using the key-value pairs to find only +devices matching particular platform or device strings. + +The strings usable as filters are: +@table @option +@item platform_profile +@item platform_version +@item platform_name +@item platform_vendor +@item platform_extensions +@item device_name +@item device_vendor +@item driver_version +@item device_version +@item device_profile +@item device_extensions +@item device_type +@end table + +The indices and filters must together uniquely select a device. + +Examples: +@table @emph +@item -init_hw_device opencl:0.1 +Choose the second device on the first platform. + +@item -init_hw_device opencl:,device_name=Foo9000 +Choose the device with a name containing the string @emph{Foo9000}. + +@item -init_hw_device opencl:1,device_type=gpu,device_extensions=cl_khr_fp16 +Choose the GPU device on the second platform supporting the @emph{cl_khr_fp16} +extension. +@end table + @end table @item -init_hw_device @var{type}[=@var{name}]@@@var{source} @@ -786,9 +824,6 @@ Do not use any hardware acceleration (the default). @item auto Automatically select the hardware acceleration method. -@item vda -Use Apple VDA hardware acceleration. - @item vdpau Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration. @@ -1132,10 +1167,6 @@ loss). By default @command{ffmpeg} attempts to read the input(s) as fast as possible. This option will slow down the reading of the input(s) to the native frame rate of the input(s). It is useful for real-time output (e.g. live streaming). -@item -loop_input -Loop over the input stream. Currently it works only for image -streams. This option is used for automatic FFserver testing. -This option is deprecated, use -loop 1. @item -loop_output @var{number_of_times} Repeatedly loop output for formats that support looping such as animated GIF (0 will loop the output infinitely). @@ -1253,6 +1284,8 @@ or as a floating point number (e.g. 0.04166, 2.0833e-5) Default value is 0. +@item -bitexact (@emph{input/output}) +Enable bitexact mode for (de)muxer and (de/en)coder @item -shortest (@emph{output}) Finish encoding when the shortest input stream ends. @item -dts_delta_threshold @@ -1375,16 +1408,6 @@ file or device. With low latency / high rate live streams, packets may be discarded if they are not read in a timely manner; raising this value can avoid it. -@item -override_ffserver (@emph{global}) -Overrides the input specifications from @command{ffserver}. Using this -option you can map any input stream to @command{ffserver} and control -many aspects of the encoding from @command{ffmpeg}. Without this -option @command{ffmpeg} will transmit to @command{ffserver} what is -requested by @command{ffserver}. - -The option is intended for cases where features are needed that cannot be -specified to @command{ffserver} but can be to @command{ffmpeg}. - @item -sdp_file @var{file} (@emph{global}) Print sdp information for an output stream to @var{file}. This allows dumping sdp information when at least one output isn't an @@ -1739,7 +1762,7 @@ ffmpeg -i src.ext -lmax 21*QP2LAMBDA dst.ext @ifset config-not-all @url{ffmpeg-all.html,ffmpeg-all}, @end ifset -@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-utils.html,ffmpeg-utils}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @@ -1758,7 +1781,7 @@ ffmpeg(1), @ifset config-not-all ffmpeg-all(1), @end ifset -ffplay(1), ffprobe(1), ffserver(1), +ffplay(1), ffprobe(1), ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) diff --git a/doc/ffplay.texi b/doc/ffplay.texi index a76bed466..c95956ea1 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -291,7 +291,7 @@ Toggle full screen. @ifset config-not-all @url{ffplay-all.html,ffmpeg-all}, @end ifset -@url{ffmpeg.html,ffmpeg}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-utils.html,ffmpeg-utils}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @@ -310,7 +310,7 @@ ffplay(1), @ifset config-not-all ffplay-all(1), @end ifset -ffmpeg(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffprobe(1), ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index e3c34babd..4e9f184a1 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -653,7 +653,7 @@ DV, GXF and AVI timecodes are available in format metadata @ifset config-not-all @url{ffprobe-all.html,ffprobe-all}, @end ifset -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffmpeg-utils.html,ffmpeg-utils}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @@ -672,7 +672,7 @@ ffprobe(1), @ifset config-not-all ffprobe-all(1), @end ifset -ffmpeg(1), ffplay(1), ffserver(1), +ffmpeg(1), ffplay(1), ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) diff --git a/doc/ffserver.conf b/doc/ffserver.conf deleted file mode 100644 index e3f99bbfb..000000000 --- a/doc/ffserver.conf +++ /dev/null @@ -1,372 +0,0 @@ -# Port on which the server is listening. You must select a different -# port from your standard HTTP web server if it is running on the same -# computer. -HTTPPort 8090 - -# Address on which the server is bound. Only useful if you have -# several network interfaces. -HTTPBindAddress 0.0.0.0 - -# Number of simultaneous HTTP connections that can be handled. It has -# to be defined *before* the MaxClients parameter, since it defines the -# MaxClients maximum limit. -MaxHTTPConnections 2000 - -# Number of simultaneous requests that can be handled. Since FFServer -# is very fast, it is more likely that you will want to leave this high -# and use MaxBandwidth, below. -MaxClients 1000 - -# This the maximum amount of kbit/sec that you are prepared to -# consume when streaming to clients. -MaxBandwidth 1000 - -# Access log file (uses standard Apache log file format) -# '-' is the standard output. -CustomLog - - -################################################################## -# Definition of the live feeds. Each live feed contains one video -# and/or audio sequence coming from an ffmpeg encoder or another -# ffserver. This sequence may be encoded simultaneously with several -# codecs at several resolutions. - - - -# You must use 'ffmpeg' to send a live feed to ffserver. In this -# example, you can type: -# -# ffmpeg http://localhost:8090/feed1.ffm - -# ffserver can also do time shifting. It means that it can stream any -# previously recorded live stream. The request should contain: -# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify -# a path where the feed is stored on disk. You also specify the -# maximum size of the feed, where zero means unlimited. Default: -# File=/tmp/feed_name.ffm FileMaxSize=5M -File /tmp/feed1.ffm -FileMaxSize 200K - -# You could specify -# ReadOnlyFile /saved/specialvideo.ffm -# This marks the file as readonly and it will not be deleted or updated. - -# Specify launch in order to start ffmpeg automatically. -# First ffmpeg must be defined with an appropriate path if needed, -# after that options can follow, but avoid adding the http:// field -#Launch ffmpeg - -# Only allow connections from localhost to the feed. -ACL allow 127.0.0.1 - - - - -################################################################## -# Now you can define each stream which will be generated from the -# original audio and video stream. Each format has a filename (here -# 'test1.mpg'). FFServer will send this stream when answering a -# request containing this filename. - - - -# coming from live feed 'feed1' -Feed feed1.ffm - -# Format of the stream : you can choose among: -# mpeg : MPEG-1 multiplexed video and audio -# mpegvideo : only MPEG-1 video -# mp2 : MPEG-2 audio (use AudioCodec to select layer 2 and 3 codec) -# ogg : Ogg format (Vorbis audio codec) -# rm : RealNetworks-compatible stream. Multiplexed audio and video. -# ra : RealNetworks-compatible stream. Audio only. -# mpjpeg : Multipart JPEG (works with Netscape without any plugin) -# jpeg : Generate a single JPEG image. -# mjpeg : Generate a M-JPEG stream. -# asf : ASF compatible streaming (Windows Media Player format). -# swf : Macromedia Flash compatible stream -# avi : AVI format (MPEG-4 video, MPEG audio sound) -Format mpeg - -# Bitrate for the audio stream. Codecs usually support only a few -# different bitrates. -AudioBitRate 32 - -# Number of audio channels: 1 = mono, 2 = stereo -AudioChannels 1 - -# Sampling frequency for audio. When using low bitrates, you should -# lower this frequency to 22050 or 11025. The supported frequencies -# depend on the selected audio codec. -AudioSampleRate 44100 - -# Bitrate for the video stream -VideoBitRate 64 - -# Ratecontrol buffer size -VideoBufferSize 40 - -# Number of frames per second -VideoFrameRate 3 - -# Size of the video frame: WxH (default: 160x128) -# The following abbreviations are defined: sqcif, qcif, cif, 4cif, qqvga, -# qvga, vga, svga, xga, uxga, qxga, sxga, qsxga, hsxga, wvga, wxga, wsxga, -# wuxga, woxga, wqsxga, wquxga, whsxga, whuxga, cga, ega, hd480, hd720, -# hd1080 -VideoSize 160x128 - -# Transmit only intra frames (useful for low bitrates, but kills frame rate). -#VideoIntraOnly - -# If non-intra only, an intra frame is transmitted every VideoGopSize -# frames. Video synchronization can only begin at an intra frame. -VideoGopSize 12 - -# More MPEG-4 parameters -# VideoHighQuality -# Video4MotionVector - -# Choose your codecs: -#AudioCodec mp2 -#VideoCodec mpeg1video - -# Suppress audio -#NoAudio - -# Suppress video -#NoVideo - -#VideoQMin 3 -#VideoQMax 31 - -# Set this to the number of seconds backwards in time to start. Note that -# most players will buffer 5-10 seconds of video, and also you need to allow -# for a keyframe to appear in the data stream. -#Preroll 15 - -# ACL: - -# You can allow ranges of addresses (or single addresses) -#ACL ALLOW - -# You can deny ranges of addresses (or single addresses) -#ACL DENY - -# You can repeat the ACL allow/deny as often as you like. It is on a per -# stream basis. The first match defines the action. If there are no matches, -# then the default is the inverse of the last ACL statement. -# -# Thus 'ACL allow localhost' only allows access from localhost. -# 'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and -# allow everybody else. - - - - -################################################################## -# Example streams - - -# Multipart JPEG - -# -#Feed feed1.ffm -#Format mpjpeg -#VideoFrameRate 2 -#VideoIntraOnly -#NoAudio -#Strict -1 -# - - -# Single JPEG - -# -#Feed feed1.ffm -#Format jpeg -#VideoFrameRate 2 -#VideoIntraOnly -##VideoSize 352x240 -#NoAudio -#Strict -1 -# - - -# Flash - -# -#Feed feed1.ffm -#Format swf -#VideoFrameRate 2 -#VideoIntraOnly -#NoAudio -# - - -# ASF compatible - - -Feed feed1.ffm -Format asf -VideoFrameRate 15 -VideoSize 352x240 -VideoBitRate 256 -VideoBufferSize 40 -VideoGopSize 30 -AudioBitRate 64 -StartSendOnKey - - - -# MP3 audio - -# -#Feed feed1.ffm -#Format mp2 -#AudioCodec mp3 -#AudioBitRate 64 -#AudioChannels 1 -#AudioSampleRate 44100 -#NoVideo -# - - -# Ogg Vorbis audio - -# -#Feed feed1.ffm -#Metadata title "Stream title" -#AudioBitRate 64 -#AudioChannels 2 -#AudioSampleRate 44100 -#NoVideo -# - - -# Real with audio only at 32 kbits - -# -#Feed feed1.ffm -#Format rm -#AudioBitRate 32 -#NoVideo -#NoAudio -# - - -# Real with audio and video at 64 kbits - -# -#Feed feed1.ffm -#Format rm -#AudioBitRate 32 -#VideoBitRate 128 -#VideoFrameRate 25 -#VideoGopSize 25 -#NoAudio -# - - -################################################################## -# A stream coming from a file: you only need to set the input -# filename and optionally a new format. Supported conversions: -# AVI -> ASF - -# -#File "/usr/local/httpd/htdocs/tlive.rm" -#NoAudio -# - -# -#File "/usr/local/httpd/htdocs/test.asf" -#NoAudio -#Metadata author "Me" -#Metadata copyright "Super MegaCorp" -#Metadata title "Test stream from disk" -#Metadata comment "Test comment" -# - - -################################################################## -# RTSP examples -# -# You can access this stream with the RTSP URL: -# rtsp://localhost:5454/test1-rtsp.mpg -# -# A non-standard RTSP redirector is also created. Its URL is: -# http://localhost:8090/test1-rtsp.rtsp - -# -#Format rtp -#File "/usr/local/httpd/htdocs/test1.mpg" -# - - -# Transcode an incoming live feed to another live feed, -# using libx264 and video presets - -# -#Format rtp -#Feed feed1.ffm -#VideoCodec libx264 -#VideoFrameRate 24 -#VideoBitRate 100 -#VideoSize 480x272 -#AVPresetVideo default -#AVPresetVideo baseline -#AVOptionVideo flags +global_header -# -#AudioCodec aac -#AudioBitRate 32 -#AudioChannels 2 -#AudioSampleRate 22050 -#AVOptionAudio flags +global_header -# - -################################################################## -# SDP/multicast examples -# -# If you want to send your stream in multicast, you must set the -# multicast address with MulticastAddress. The port and the TTL can -# also be set. -# -# An SDP file is automatically generated by ffserver by adding the -# 'sdp' extension to the stream name (here -# http://localhost:8090/test1-sdp.sdp). You should usually give this -# file to your player to play the stream. -# -# The 'NoLoop' option can be used to avoid looping when the stream is -# terminated. - -# -#Format rtp -#File "/usr/local/httpd/htdocs/test1.mpg" -#MulticastAddress 224.124.0.1 -#MulticastPort 5000 -#MulticastTTL 16 -#NoLoop -# - - -################################################################## -# Special streams - -# Server status - - -Format status - -# Only allow local people to get the status -ACL allow localhost -ACL allow 192.168.0.0 192.168.255.255 - -#FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico - - - -# Redirect index.html to the appropriate site - - -URL http://www.ffmpeg.org/ - diff --git a/doc/ffserver.texi b/doc/ffserver.texi deleted file mode 100644 index b3e1f1d7e..000000000 --- a/doc/ffserver.texi +++ /dev/null @@ -1,923 +0,0 @@ -\input texinfo @c -*- texinfo -*- -@documentencoding UTF-8 - -@settitle ffserver Documentation -@titlepage -@center @titlefont{ffserver Documentation} -@end titlepage - -@top - -@contents - -@chapter Synopsis - -ffserver [@var{options}] - -@chapter Description -@c man begin DESCRIPTION - -@command{ffserver} is a streaming server for both audio and video. -It supports several live feeds, streaming from files and time shifting -on live feeds. You can seek to positions in the past on each live -feed, provided you specify a big enough feed storage. - -@command{ffserver} is configured through a configuration file, which -is read at startup. If not explicitly specified, it will read from -@file{/etc/ffserver.conf}. - -@command{ffserver} receives prerecorded files or FFM streams from some -@command{ffmpeg} instance as input, then streams them over -RTP/RTSP/HTTP. - -An @command{ffserver} instance will listen on some port as specified -in the configuration file. You can launch one or more instances of -@command{ffmpeg} and send one or more FFM streams to the port where -ffserver is expecting to receive them. Alternately, you can make -@command{ffserver} launch such @command{ffmpeg} instances at startup. - -Input streams are called feeds, and each one is specified by a -@code{} section in the configuration file. - -For each feed you can have different output streams in various -formats, each one specified by a @code{} section in the -configuration file. - -@chapter Detailed description - -@command{ffserver} works by forwarding streams encoded by -@command{ffmpeg}, or pre-recorded streams which are read from disk. - -Precisely, @command{ffserver} acts as an HTTP server, accepting POST -requests from @command{ffmpeg} to acquire the stream to publish, and -serving RTSP clients or HTTP clients GET requests with the stream -media content. - -A feed is an @ref{FFM} stream created by @command{ffmpeg}, and sent to -a port where @command{ffserver} is listening. - -Each feed is identified by a unique name, corresponding to the name -of the resource published on @command{ffserver}, and is configured by -a dedicated @code{Feed} section in the configuration file. - -The feed publish URL is given by: -@example -http://@var{ffserver_ip_address}:@var{http_port}/@var{feed_name} -@end example - -where @var{ffserver_ip_address} is the IP address of the machine where -@command{ffserver} is installed, @var{http_port} is the port number of -the HTTP server (configured through the @option{HTTPPort} option), and -@var{feed_name} is the name of the corresponding feed defined in the -configuration file. - -Each feed is associated to a file which is stored on disk. This stored -file is used to send pre-recorded data to a player as fast as -possible when new content is added in real-time to the stream. - -A "live-stream" or "stream" is a resource published by -@command{ffserver}, and made accessible through the HTTP protocol to -clients. - -A stream can be connected to a feed, or to a file. In the first case, -the published stream is forwarded from the corresponding feed -generated by a running instance of @command{ffmpeg}, in the second -case the stream is read from a pre-recorded file. - -Each stream is identified by a unique name, corresponding to the name -of the resource served by @command{ffserver}, and is configured by -a dedicated @code{Stream} section in the configuration file. - -The stream access HTTP URL is given by: -@example -http://@var{ffserver_ip_address}:@var{http_port}/@var{stream_name}[@var{options}] -@end example - -The stream access RTSP URL is given by: -@example -http://@var{ffserver_ip_address}:@var{rtsp_port}/@var{stream_name}[@var{options}] -@end example - -@var{stream_name} is the name of the corresponding stream defined in -the configuration file. @var{options} is a list of options specified -after the URL which affects how the stream is served by -@command{ffserver}. @var{http_port} and @var{rtsp_port} are the HTTP -and RTSP ports configured with the options @var{HTTPPort} and -@var{RTSPPort} respectively. - -In case the stream is associated to a feed, the encoding parameters -must be configured in the stream configuration. They are sent to -@command{ffmpeg} when setting up the encoding. This allows -@command{ffserver} to define the encoding parameters used by -the @command{ffmpeg} encoders. - -The @command{ffmpeg} @option{override_ffserver} commandline option -allows one to override the encoding parameters set by the server. - -Multiple streams can be connected to the same feed. - -For example, you can have a situation described by the following -graph: - -@verbatim - _________ __________ - | | | | -ffmpeg 1 -----| feed 1 |-----| stream 1 | - \ |_________|\ |__________| - \ \ - \ \ __________ - \ \ | | - \ \| stream 2 | - \ |__________| - \ - \ _________ __________ - \ | | | | - \| feed 2 |-----| stream 3 | - |_________| |__________| - - _________ __________ - | | | | -ffmpeg 2 -----| feed 3 |-----| stream 4 | - |_________| |__________| - - _________ __________ - | | | | - | file 1 |-----| stream 5 | - |_________| |__________| - -@end verbatim - -@anchor{FFM} -@section FFM, FFM2 formats - -FFM and FFM2 are formats used by ffserver. They allow storing a wide variety of -video and audio streams and encoding options, and can store a moving time segment -of an infinite movie or a whole movie. - -FFM is version specific, and there is limited compatibility of FFM files -generated by one version of ffmpeg/ffserver and another version of -ffmpeg/ffserver. It may work but it is not guaranteed to work. - -FFM2 is extensible while maintaining compatibility and should work between -differing versions of tools. FFM2 is the default. - -@section Status stream - -@command{ffserver} supports an HTTP interface which exposes the -current status of the server. - -Simply point your browser to the address of the special status stream -specified in the configuration file. - -For example if you have: -@example - -Format status - -# Only allow local people to get the status -ACL allow localhost -ACL allow 192.168.0.0 192.168.255.255 - -@end example - -then the server will post a page with the status information when -the special stream @file{status.html} is requested. - -@section How do I make it work? - -As a simple test, just run the following two command lines where INPUTFILE -is some file which you can decode with ffmpeg: - -@example -ffserver -f doc/ffserver.conf & -ffmpeg -i INPUTFILE http://localhost:8090/feed1.ffm -@end example - -At this point you should be able to go to your Windows machine and fire up -Windows Media Player (WMP). Go to Open URL and enter - -@example - http://:8090/test.asf -@end example - -You should (after a short delay) see video and hear audio. - -WARNING: trying to stream test1.mpg doesn't work with WMP as it tries to -transfer the entire file before starting to play. -The same is true of AVI files. - -You should edit the @file{ffserver.conf} file to suit your needs (in -terms of frame rates etc). Then install @command{ffserver} and -@command{ffmpeg}, write a script to start them up, and off you go. - -@section What else can it do? - -You can replay video from .ffm files that was recorded earlier. -However, there are a number of caveats, including the fact that the -ffserver parameters must match the original parameters used to record the -file. If they do not, then ffserver deletes the file before recording into it. -(Now that I write this, it seems broken). - -You can fiddle with many of the codec choices and encoding parameters, and -there are a bunch more parameters that you cannot control. Post a message -to the mailing list if there are some 'must have' parameters. Look in -ffserver.conf for a list of the currently available controls. - -It will automatically generate the ASX or RAM files that are often used -in browsers. These files are actually redirections to the underlying ASF -or RM file. The reason for this is that the browser often fetches the -entire file before starting up the external viewer. The redirection files -are very small and can be transferred quickly. [The stream itself is -often 'infinite' and thus the browser tries to download it and never -finishes.] - -@section Tips - -* When you connect to a live stream, most players (WMP, RA, etc) want to -buffer a certain number of seconds of material so that they can display the -signal continuously. However, ffserver (by default) starts sending data -in realtime. This means that there is a pause of a few seconds while the -buffering is being done by the player. The good news is that this can be -cured by adding a '?buffer=5' to the end of the URL. This means that the -stream should start 5 seconds in the past -- and so the first 5 seconds -of the stream are sent as fast as the network will allow. It will then -slow down to real time. This noticeably improves the startup experience. - -You can also add a 'Preroll 15' statement into the ffserver.conf that will -add the 15 second prebuffering on all requests that do not otherwise -specify a time. In addition, ffserver will skip frames until a key_frame -is found. This further reduces the startup delay by not transferring data -that will be discarded. - -@section Why does the ?buffer / Preroll stop working after a time? - -It turns out that (on my machine at least) the number of frames successfully -grabbed is marginally less than the number that ought to be grabbed. This -means that the timestamp in the encoded data stream gets behind realtime. -This means that if you say 'Preroll 10', then when the stream gets 10 -or more seconds behind, there is no Preroll left. - -Fixing this requires a change in the internals of how timestamps are -handled. - -@section Does the @code{?date=} stuff work. - -Yes (subject to the limitation outlined above). Also note that whenever you -start ffserver, it deletes the ffm file (if any parameters have changed), -thus wiping out what you had recorded before. - -The format of the @code{?date=xxxxxx} is fairly flexible. You should use one -of the following formats (the 'T' is literal): - -@example -* YYYY-MM-DDTHH:MM:SS (localtime) -* YYYY-MM-DDTHH:MM:SSZ (UTC) -@end example - -You can omit the YYYY-MM-DD, and then it refers to the current day. However -note that @samp{?date=16:00:00} refers to 16:00 on the current day -- this -may be in the future and so is unlikely to be useful. - -You use this by adding the ?date= to the end of the URL for the stream. -For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}. -@c man end - -@chapter Options -@c man begin OPTIONS - -@include fftools-common-opts.texi - -@section Main options - -@table @option -@item -f @var{configfile} -Read configuration file @file{configfile}. If not specified it will -read by default from @file{/etc/ffserver.conf}. - -@item -n -Enable no-launch mode. This option disables all the @code{Launch} -directives within the various @code{} sections. Since -@command{ffserver} will not launch any @command{ffmpeg} instances, you -will have to launch them manually. - -@item -d -Enable debug mode. This option increases log verbosity, and directs -log messages to stdout. When specified, the @option{CustomLog} option -is ignored. -@end table - -@chapter Configuration file syntax - -@command{ffserver} reads a configuration file containing global -options and settings for each stream and feed. - -The configuration file consists of global options and dedicated -sections, which must be introduced by "<@var{SECTION_NAME} -@var{ARGS}>" on a separate line and must be terminated by a line in -the form "". @var{ARGS} is optional. - -Currently the following sections are recognized: @samp{Feed}, -@samp{Stream}, @samp{Redirect}. - -A line starting with @code{#} is ignored and treated as a comment. - -Name of options and sections are case-insensitive. - -@section ACL syntax -An ACL (Access Control List) specifies the address which are allowed -to access a given stream, or to write a given feed. - -It accepts the following forms -@itemize -@item -Allow/deny access to @var{address}. -@example -ACL ALLOW
-ACL DENY
-@end example - -@item -Allow/deny access to ranges of addresses from @var{first_address} to -@var{last_address}. -@example -ACL ALLOW -ACL DENY -@end example -@end itemize - -You can repeat the ACL allow/deny as often as you like. It is on a per -stream basis. The first match defines the action. If there are no matches, -then the default is the inverse of the last ACL statement. - -Thus 'ACL allow localhost' only allows access from localhost. -'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and -allow everybody else. - -@section Global options -@table @option -@item HTTPPort @var{port_number} -@item Port @var{port_number} -@item RTSPPort @var{port_number} - -@var{HTTPPort} sets the HTTP server listening TCP port number, -@var{RTSPPort} sets the RTSP server listening TCP port number. - -@var{Port} is the equivalent of @var{HTTPPort} and is deprecated. - -You must select a different port from your standard HTTP web server if -it is running on the same computer. - -If not specified, no corresponding server will be created. - -@item HTTPBindAddress @var{ip_address} -@item BindAddress @var{ip_address} -@item RTSPBindAddress @var{ip_address} -Set address on which the HTTP/RTSP server is bound. Only useful if you -have several network interfaces. - -@var{BindAddress} is the equivalent of @var{HTTPBindAddress} and is -deprecated. - -@item MaxHTTPConnections @var{n} -Set number of simultaneous HTTP connections that can be handled. It -has to be defined @emph{before} the @option{MaxClients} parameter, -since it defines the @option{MaxClients} maximum limit. - -Default value is 2000. - -@item MaxClients @var{n} -Set number of simultaneous requests that can be handled. Since -@command{ffserver} is very fast, it is more likely that you will want -to leave this high and use @option{MaxBandwidth}. - -Default value is 5. - -@item MaxBandwidth @var{kbps} -Set the maximum amount of kbit/sec that you are prepared to consume -when streaming to clients. - -Default value is 1000. - -@item CustomLog @var{filename} -Set access log file (uses standard Apache log file format). '-' is the -standard output. - -If not specified @command{ffserver} will produce no log. - -In case the commandline option @option{-d} is specified this option is -ignored, and the log is written to standard output. - -@item NoDaemon -Set no-daemon mode. This option is currently ignored since now -@command{ffserver} will always work in no-daemon mode, and is -deprecated. - -@item UseDefaults -@item NoDefaults -Control whether default codec options are used for the all streams or not. -Each stream may overwrite this setting for its own. Default is @var{UseDefaults}. -The last occurrence overrides the previous if multiple definitions exist. -@end table - -@section Feed section - -A Feed section defines a feed provided to @command{ffserver}. - -Each live feed contains one video and/or audio sequence coming from an -@command{ffmpeg} encoder or another @command{ffserver}. This sequence -may be encoded simultaneously with several codecs at several -resolutions. - -A feed instance specification is introduced by a line in the form: -@example - -@end example - -where @var{FEED_FILENAME} specifies the unique name of the FFM stream. - -The following options are recognized within a Feed section. - -@table @option -@item File @var{filename} -@item ReadOnlyFile @var{filename} -Set the path where the feed file is stored on disk. - -If not specified, the @file{/tmp/FEED.ffm} is assumed, where -@var{FEED} is the feed name. - -If @option{ReadOnlyFile} is used the file is marked as read-only and -it will not be deleted or updated. - -@item Truncate -Truncate the feed file, rather than appending to it. By default -@command{ffserver} will append data to the file, until the maximum -file size value is reached (see @option{FileMaxSize} option). - -@item FileMaxSize @var{size} -Set maximum size of the feed file in bytes. 0 means unlimited. The -postfixes @code{K} (2^10), @code{M} (2^20), and @code{G} (2^30) are -recognized. - -Default value is 5M. - -@item Launch @var{args} -Launch an @command{ffmpeg} command when creating @command{ffserver}. - -@var{args} must be a sequence of arguments to be provided to an -@command{ffmpeg} instance. The first provided argument is ignored, and -it is replaced by a path with the same dirname of the @command{ffserver} -instance, followed by the remaining argument and terminated with a -path corresponding to the feed. - -When the launched process exits, @command{ffserver} will launch -another program instance. - -In case you need a more complex @command{ffmpeg} configuration, -e.g. if you need to generate multiple FFM feeds with a single -@command{ffmpeg} instance, you should launch @command{ffmpeg} by hand. - -This option is ignored in case the commandline option @option{-n} is -specified. - -@item ACL @var{spec} -Specify the list of IP address which are allowed or denied to write -the feed. Multiple ACL options can be specified. -@end table - -@section Stream section - -A Stream section defines a stream provided by @command{ffserver}, and -identified by a single name. - -The stream is sent when answering a request containing the stream -name. - -A stream section must be introduced by the line: -@example - -@end example - -where @var{STREAM_NAME} specifies the unique name of the stream. - -The following options are recognized within a Stream section. - -Encoding options are marked with the @emph{encoding} tag, and they are -used to set the encoding parameters, and are mapped to libavcodec -encoding options. Not all encoding options are supported, in -particular it is not possible to set encoder private options. In order -to override the encoding options specified by @command{ffserver}, you -can use the @command{ffmpeg} @option{override_ffserver} commandline -option. - -Only one of the @option{Feed} and @option{File} options should be set. - -@table @option -@item Feed @var{feed_name} -Set the input feed. @var{feed_name} must correspond to an existing -feed defined in a @code{Feed} section. - -When this option is set, encoding options are used to setup the -encoding operated by the remote @command{ffmpeg} process. - -@item File @var{filename} -Set the filename of the pre-recorded input file to stream. - -When this option is set, encoding options are ignored and the input -file content is re-streamed as is. - -@item Format @var{format_name} -Set the format of the output stream. - -Must be the name of a format recognized by FFmpeg. If set to -@samp{status}, it is treated as a status stream. - -@item InputFormat @var{format_name} -Set input format. If not specified, it is automatically guessed. - -@item Preroll @var{n} -Set this to the number of seconds backwards in time to start. Note that -most players will buffer 5-10 seconds of video, and also you need to allow -for a keyframe to appear in the data stream. - -Default value is 0. - -@item StartSendOnKey -Do not send stream until it gets the first key frame. By default -@command{ffserver} will send data immediately. - -@item MaxTime @var{n} -Set the number of seconds to run. This value set the maximum duration -of the stream a client will be able to receive. - -A value of 0 means that no limit is set on the stream duration. - -@item ACL @var{spec} -Set ACL for the stream. - -@item DynamicACL @var{spec} - -@item RTSPOption @var{option} - -@item MulticastAddress @var{address} - -@item MulticastPort @var{port} - -@item MulticastTTL @var{integer} - -@item NoLoop - -@item FaviconURL @var{url} -Set favicon (favourite icon) for the server status page. It is ignored -for regular streams. - -@item Author @var{value} -@item Comment @var{value} -@item Copyright @var{value} -@item Title @var{value} -Set metadata corresponding to the option. All these options are -deprecated in favor of @option{Metadata}. - -@item Metadata @var{key} @var{value} -Set metadata value on the output stream. - -@item UseDefaults -@item NoDefaults -Control whether default codec options are used for the stream or not. -Default is @var{UseDefaults} unless disabled globally. - -@item NoAudio -@item NoVideo -Suppress audio/video. - -@item AudioCodec @var{codec_name} (@emph{encoding,audio}) -Set audio codec. - -@item AudioBitRate @var{rate} (@emph{encoding,audio}) -Set bitrate for the audio stream in kbits per second. - -@item AudioChannels @var{n} (@emph{encoding,audio}) -Set number of audio channels. - -@item AudioSampleRate @var{n} (@emph{encoding,audio}) -Set sampling frequency for audio. When using low bitrates, you should -lower this frequency to 22050 or 11025. The supported frequencies -depend on the selected audio codec. - -@item AVOptionAudio [@var{codec}:]@var{option} @var{value} (@emph{encoding,audio}) -Set generic or private option for audio stream. -Private option must be prefixed with codec name or codec must be defined before. - -@item AVPresetAudio @var{preset} (@emph{encoding,audio}) -Set preset for audio stream. - -@item VideoCodec @var{codec_name} (@emph{encoding,video}) -Set video codec. - -@item VideoBitRate @var{n} (@emph{encoding,video}) -Set bitrate for the video stream in kbits per second. - -@item VideoBitRateRange @var{range} (@emph{encoding,video}) -Set video bitrate range. - -A range must be specified in the form @var{minrate}-@var{maxrate}, and -specifies the @option{minrate} and @option{maxrate} encoding options -expressed in kbits per second. - -@item VideoBitRateRangeTolerance @var{n} (@emph{encoding,video}) -Set video bitrate tolerance in kbits per second. - -@item PixelFormat @var{pixel_format} (@emph{encoding,video}) -Set video pixel format. - -@item Debug @var{integer} (@emph{encoding,video}) -Set video @option{debug} encoding option. - -@item Strict @var{integer} (@emph{encoding,video}) -Set video @option{strict} encoding option. - -@item VideoBufferSize @var{n} (@emph{encoding,video}) -Set ratecontrol buffer size, expressed in KB. - -@item VideoFrameRate @var{n} (@emph{encoding,video}) -Set number of video frames per second. - -@item VideoSize (@emph{encoding,video}) -Set size of the video frame, must be an abbreviation or in the form -@var{W}x@var{H}. See @ref{video size syntax,,the Video size section -in the ffmpeg-utils(1) manual,ffmpeg-utils}. - -Default value is @code{160x128}. - -@item VideoIntraOnly (@emph{encoding,video}) -Transmit only intra frames (useful for low bitrates, but kills frame rate). - -@item VideoGopSize @var{n} (@emph{encoding,video}) -If non-intra only, an intra frame is transmitted every VideoGopSize -frames. Video synchronization can only begin at an intra frame. - -@item VideoTag @var{tag} (@emph{encoding,video}) -Set video tag. - -@item VideoHighQuality (@emph{encoding,video}) -@item Video4MotionVector (@emph{encoding,video}) - -@item BitExact (@emph{encoding,video}) -Set bitexact encoding flag. - -@item IdctSimple (@emph{encoding,video}) -Set simple IDCT algorithm. - -@item Qscale @var{n} (@emph{encoding,video}) -Enable constant quality encoding, and set video qscale (quantization -scale) value, expressed in @var{n} QP units. - -@item VideoQMin @var{n} (@emph{encoding,video}) -@item VideoQMax @var{n} (@emph{encoding,video}) -Set video qmin/qmax. - -@item VideoQDiff @var{integer} (@emph{encoding,video}) -Set video @option{qdiff} encoding option. - -@item LumiMask @var{float} (@emph{encoding,video}) -@item DarkMask @var{float} (@emph{encoding,video}) -Set @option{lumi_mask}/@option{dark_mask} encoding options. - -@item AVOptionVideo [@var{codec}:]@var{option} @var{value} (@emph{encoding,video}) -Set generic or private option for video stream. -Private option must be prefixed with codec name or codec must be defined before. - -@item AVPresetVideo @var{preset} (@emph{encoding,video}) -Set preset for video stream. - -@var{preset} must be the path of a preset file. -@end table - -@subsection Server status stream - -A server status stream is a special stream which is used to show -statistics about the @command{ffserver} operations. - -It must be specified setting the option @option{Format} to -@samp{status}. - -@section Redirect section - -A redirect section specifies where to redirect the requested URL to -another page. - -A redirect section must be introduced by the line: -@example - -@end example - -where @var{NAME} is the name of the page which should be redirected. - -It only accepts the option @option{URL}, which specify the redirection -URL. - -@chapter Stream examples - -@itemize -@item -Multipart JPEG -@example - -Feed feed1.ffm -Format mpjpeg -VideoFrameRate 2 -VideoIntraOnly -NoAudio -Strict -1 - -@end example - -@item -Single JPEG -@example - -Feed feed1.ffm -Format jpeg -VideoFrameRate 2 -VideoIntraOnly -VideoSize 352x240 -NoAudio -Strict -1 - -@end example - -@item -Flash -@example - -Feed feed1.ffm -Format swf -VideoFrameRate 2 -VideoIntraOnly -NoAudio - -@end example - -@item -ASF compatible -@example - -Feed feed1.ffm -Format asf -VideoFrameRate 15 -VideoSize 352x240 -VideoBitRate 256 -VideoBufferSize 40 -VideoGopSize 30 -AudioBitRate 64 -StartSendOnKey - -@end example - -@item -MP3 audio -@example - -Feed feed1.ffm -Format mp2 -AudioCodec mp3 -AudioBitRate 64 -AudioChannels 1 -AudioSampleRate 44100 -NoVideo - -@end example - -@item -Ogg Vorbis audio -@example - -Feed feed1.ffm -Metadata title "Stream title" -AudioBitRate 64 -AudioChannels 2 -AudioSampleRate 44100 -NoVideo - -@end example - -@item -Real with audio only at 32 kbits -@example - -Feed feed1.ffm -Format rm -AudioBitRate 32 -NoVideo - -@end example - -@item -Real with audio and video at 64 kbits -@example - -Feed feed1.ffm -Format rm -AudioBitRate 32 -VideoBitRate 128 -VideoFrameRate 25 -VideoGopSize 25 - -@end example - -@item -For stream coming from a file: you only need to set the input filename -and optionally a new format. - -@example - -File "/usr/local/httpd/htdocs/tlive.rm" -NoAudio - -@end example - -@example - -File "/usr/local/httpd/htdocs/test.asf" -NoAudio -Metadata author "Me" -Metadata copyright "Super MegaCorp" -Metadata title "Test stream from disk" -Metadata comment "Test comment" - -@end example -@end itemize - -@c man end - -@include config.texi -@ifset config-all -@ifset config-avutil -@include utils.texi -@end ifset -@ifset config-avcodec -@include codecs.texi -@include bitstream_filters.texi -@end ifset -@ifset config-avformat -@include formats.texi -@include protocols.texi -@end ifset -@ifset config-avdevice -@include devices.texi -@end ifset -@ifset config-swresample -@include resampler.texi -@end ifset -@ifset config-swscale -@include scaler.texi -@end ifset -@ifset config-avfilter -@include filters.texi -@end ifset -@end ifset - -@chapter See Also - -@ifhtml -@ifset config-all -@url{ffserver.html,ffserver}, -@end ifset -@ifset config-not-all -@url{ffserver-all.html,ffserver-all}, -@end ifset -the @file{doc/ffserver.conf} example, -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, -@url{ffmpeg-utils.html,ffmpeg-utils}, -@url{ffmpeg-scaler.html,ffmpeg-scaler}, -@url{ffmpeg-resampler.html,ffmpeg-resampler}, -@url{ffmpeg-codecs.html,ffmpeg-codecs}, -@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters}, -@url{ffmpeg-formats.html,ffmpeg-formats}, -@url{ffmpeg-devices.html,ffmpeg-devices}, -@url{ffmpeg-protocols.html,ffmpeg-protocols}, -@url{ffmpeg-filters.html,ffmpeg-filters} -@end ifhtml - -@ifnothtml -@ifset config-all -ffserver(1), -@end ifset -@ifset config-not-all -ffserver-all(1), -@end ifset -the @file{doc/ffserver.conf} example, ffmpeg(1), ffplay(1), ffprobe(1), -ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), -ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), -ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) -@end ifnothtml - -@include authors.texi - -@ignore - -@setfilename ffserver -@settitle ffserver video server - -@end ignore - -@bye diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 2eff33a36..185ec218d 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -315,51 +315,6 @@ Possible flags for this option are: @item k8 @end table @end table - -@item -opencl_bench -This option is used to benchmark all available OpenCL devices and print the -results. This option is only available when FFmpeg has been compiled with -@code{--enable-opencl}. - -When FFmpeg is configured with @code{--enable-opencl}, the options for the -global OpenCL context are set via @option{-opencl_options}. See the -"OpenCL Options" section in the ffmpeg-utils manual for the complete list of -supported options. Amongst others, these options include the ability to select -a specific platform and device to run the OpenCL code on. By default, FFmpeg -will run on the first device of the first platform. While the options for the -global OpenCL context provide flexibility to the user in selecting the OpenCL -device of their choice, most users would probably want to select the fastest -OpenCL device for their system. - -This option assists the selection of the most efficient configuration by -identifying the appropriate device for the user's system. The built-in -benchmark is run on all the OpenCL devices and the performance is measured for -each device. The devices in the results list are sorted based on their -performance with the fastest device listed first. The user can subsequently -invoke @command{ffmpeg} using the device deemed most appropriate via -@option{-opencl_options} to obtain the best performance for the OpenCL -accelerated code. - -Typical usage to use the fastest OpenCL device involve the following steps. - -Run the command: -@example -ffmpeg -opencl_bench -@end example -Note down the platform ID (@var{pidx}) and device ID (@var{didx}) of the first -i.e. fastest device in the list. -Select the platform and device using the command: -@example -ffmpeg -opencl_options platform_idx=@var{pidx}:device_idx=@var{didx} ... -@end example - -@item -opencl_options options (@emph{global}) -Set OpenCL environment options. This option is only available when -FFmpeg has been compiled with @code{--enable-opencl}. - -@var{options} must be a list of @var{key}=@var{value} option pairs -separated by ':'. See the ``OpenCL Options'' section in the -ffmpeg-utils manual for the list of supported options. @end table @section AVOptions diff --git a/doc/filters.texi b/doc/filters.texi index e26dde4b1..bd93e0ab8 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -429,6 +429,16 @@ How much to use compressed signal in output. Default is 1. Range is between 0 and 1. @end table +@section acontrast +Simple audio dynamic range commpression/expansion filter. + +The filter accepts the following options: + +@table @option +@item contrast +Set contrast. Default is 33. Allowed range is between 0 and 100. +@end table + @section acopy Copy the input audio source unchanged to the output. This is mainly useful for @@ -916,6 +926,7 @@ afftfilt="1-clip((b/nb)*b,0,1)" @end example @end itemize +@anchor{afir} @section afir Apply an arbitrary Frequency Impulse Response filter. @@ -1049,6 +1060,89 @@ the reduction. Default is @code{average}. Can be @code{average} or @code{maximum}. @end table +@section aiir + +Apply an arbitrary Infinite Impulse Response filter. + +It accepts the following parameters: + +@table @option +@item z +Set numerator/zeros coefficients. + +@item p +Set denominator/poles coefficients. + +@item k +Set channels gains. + +@item dry_gain +Set input gain. + +@item wet_gain +Set output gain. + +@item f +Set coefficients format. + +@table @samp +@item tf +transfer function +@item zp +Z-plane zeros/poles, cartesian (default) +@item pr +Z-plane zeros/poles, polar radians +@item pd +Z-plane zeros/poles, polar degrees +@end table + +@item r +Set kind of processing. +Can be @code{d} - direct or @code{s} - serial cascading. Defauls is @code{s}. + +@item e +Set filtering precision. + +@table @samp +@item dbl +double-precision floating-point (default) +@item flt +single-precision floating-point +@item i32 +32-bit integers +@item i16 +16-bit integers +@end table + +@end table + +Coefficients in @code{tf} format are separated by spaces and are in ascending +order. + +Coefficients in @code{zp} format are separated by spaces and order of coefficients +doesn't matter. Coefficients in @code{zp} format are complex numbers with @var{i} +imaginary unit. + +Different coefficients and gains can be provided for every channel, in such case +use '|' to separate coefficients or gains. Last provided coefficients will be +used for all remaining channels. + +@subsection Examples + +@itemize +@item +Apply 2 pole elliptic notch at arround 5000Hz for 48000 Hz sample rate: +@example +aiir=k=1:z=7.957584807809675810E-1 -2.575128568908332300 3.674839853930788710 -2.57512875289799137 7.957586296317130880E-1:p=1 -2.86950072432325953 3.63022088054647218 -2.28075678147272232 6.361362326477423500E-1:f=tf:r=d +@end example + +@item +Same as above but in @code{zp} format: +@example +aiir=k=0.79575848078096756:z=0.80918701+0.58773007i 0.80918701-0.58773007i 0.80884700+0.58784055i 0.80884700-0.58784055i:p=0.63892345+0.59951235i 0.63892345-0.59951235i 0.79582691+0.44198673i 0.79582691-0.44198673i:f=zp:r=s +@end example +@end itemize + @section alimiter The limiter prevents an input signal from rising over a desired threshold. @@ -1117,6 +1211,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1126,6 +1222,23 @@ Specify the band-width of a filter in width_type units. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change allpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change allpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change allpass width. +Syntax for the command is : "@var{width}" +@end table + @section aloop Loop audio samples. @@ -1134,13 +1247,14 @@ The filter accepts the following options: @table @option @item loop -Set the number of loops. +Set the number of loops. Setting this value to -1 will result in infinite loops. +Default is 0. @item size -Set maximal number of samples. +Set maximal number of samples. Default is 0. @item start -Set first sample of loop. +Set first sample of loop. Default is 0. @end table @anchor{amerge} @@ -1856,6 +1970,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1865,6 +1981,23 @@ Specify the band-width of a filter in width_type units. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change bandpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change bandpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change bandpass width. +Syntax for the command is : "@var{width}" +@end table + @section bandreject Apply a two-pole Butterworth band-reject filter with central @@ -1888,6 +2021,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1897,6 +2032,23 @@ Specify the band-width of a filter in width_type units. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change bandreject frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change bandreject width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change bandreject width. +Syntax for the command is : "@var{width}" +@end table + @section bass Boost or cut the bass (lower) frequencies of the audio using a two-pole @@ -1927,6 +2079,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1936,6 +2090,27 @@ Determine how steep is the filter's shelf transition. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change bass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change bass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change bass width. +Syntax for the command is : "@var{width}" + +@item gain, g +Change bass gain. +Syntax for the command is : "@var{gain}" +@end table + @section biquad Apply a biquad IIR filter with the given coefficients. @@ -1944,6 +2119,20 @@ are the numerator and denominator coefficients respectively. and @var{channels}, @var{c} specify which channels to filter, by default all available are filtered. +@subsection Commands + +This filter supports the following commands: +@table @option +@item a0 +@item a1 +@item a2 +@item b0 +@item b1 +@item b2 +Change biquad parameter. +Syntax for the command is : "@var{value}" +@end table + @section bs2b Bauer stereo to binaural transformation, which improves headphone listening of stereo audio records. @@ -2545,6 +2734,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -2573,6 +2764,27 @@ equalizer=f=1000:t=q:w=1:g=2,equalizer=f=100:t=q:w=2:g=-5 @end example @end itemize +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change equalizer frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change equalizer width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change equalizer width. +Syntax for the command is : "@var{width}" + +@item gain, g +Change equalizer gain. +Syntax for the command is : "@var{gain}" +@end table + @section extrastereo Linearly increases the difference between left and right channels which @@ -2961,6 +3173,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -2972,6 +3186,23 @@ The default is 0.707q and gives a Butterworth response. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change highpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change highpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change highpass width. +Syntax for the command is : "@var{width}" +@end table + @section join Join multiple input streams into one multi-channel stream. @@ -3250,6 +3481,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -3270,6 +3503,98 @@ lowpass=c=LFE @end example @end itemize +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change lowpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change lowpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change lowpass width. +Syntax for the command is : "@var{width}" +@end table + +@section lv2 + +Load a LV2 (LADSPA Version 2) plugin. + +To enable compilation of this filter you need to configure FFmpeg with +@code{--enable-lv2}. + +@table @option +@item plugin, p +Specifies the plugin URI. You may need to escape ':'. + +@item controls, c +Set the '|' separated list of controls which are zero or more floating point +values that determine the behavior of the loaded plugin (for example delay, +threshold or gain). +If @option{controls} is set to @code{help}, all available controls and +their valid ranges are printed. + +@item sample_rate, s +Specify the sample rate, default to 44100. Only used if plugin have +zero inputs. + +@item nb_samples, n +Set the number of samples per channel per each output frame, default +is 1024. Only used if plugin have zero inputs. + +@item duration, d +Set the minimum duration of the sourced audio. See +@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} +for the accepted syntax. +Note that the resulting duration may be greater than the specified duration, +as the generated audio is always cut at the end of a complete frame. +If not specified, or the expressed duration is negative, the audio is +supposed to be generated forever. +Only used if plugin have zero inputs. +@end table + +@subsection Examples + +@itemize +@item +Apply bass enhancer plugin from Calf: +@example +lv2=p=http\\\\://calf.sourceforge.net/plugins/BassEnhancer:c=amount=2 +@end example + +@item +Apply bass vinyl plugin from Calf: +@example +lv2=p=http\\\\://calf.sourceforge.net/plugins/Vinyl:c=drone=0.2|aging=0.5 +@end example + +@item +Apply bit crusher plugin from ArtyFX: +@example +lv2=p=http\\\\://www.openavproductions.com/artyfx#bitta:c=crush=0.3 +@end example +@end itemize + +@section mcompand +Multiband Compress or expand the audio's dynamic range. + +The input audio is divided into bands using 4th order Linkwitz-Riley IIRs. +This is akin to the crossover of a loudspeaker, and results in flat frequency +response when absent compander action. + +It accepts the following parameters: + +@table @option +@item args +This option syntax is: +attack,decay,[attack,decay..] soft-knee points crossover_frequency [delay [initial_volume [gain]]] | attack,decay ... +For explanation of each item refer to compand filter documentation. +@end table + @anchor{pan} @section pan @@ -4067,6 +4392,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -4076,6 +4403,27 @@ Determine how steep is the filter's shelf transition. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change treble frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change treble width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change treble width. +Syntax for the command is : "@var{width}" + +@item gain, g +Change treble gain. +Syntax for the command is : "@var{gain}" +@end table + @section tremolo Sinusoidal amplitude modulation. @@ -4512,7 +4860,7 @@ Synthesize a voice utterance using the libflite library. To enable compilation of this filter you need to configure FFmpeg with @code{--enable-libflite}. -Note that the flite library is not thread-safe. +Note that versions of the flite library prior to 2.0 are not thread-safe. The filter accepts the following options: @@ -4567,7 +4915,7 @@ ffplay -f lavfi flite=text='No more be grieved for which that thou hast done.' @end itemize For more information about libflite, check: -@url{http://www.speech.cs.cmu.edu/flite/} +@url{http://www.festvox.org/flite/} @section anoisesrc @@ -4609,6 +4957,33 @@ anoisesrc=d=60:c=pink:r=44100:a=0.5 @end example @end itemize +@section hilbert + +Generate odd-tap Hilbert transform FIR coefficients. + +The resulting stream can be used with @ref{afir} filter for phase-shifting +the signal by 90 degrees. + +This is used in many matrix coding schemes and for analytic signal generation. +The process is often written as a multiplication by i (or j), the imaginary unit. + +The filter accepts the following options: + +@table @option + +@item sample_rate, s +Set sample rate, default is 44100. + +@item taps, t +Set length of FIR filter, default is 22051. + +@item nb_samples, n +Set number of samples per each frame. + +@item win_func, w +Set window function to be used when generating FIR coefficients. +@end table + @section sine Generate an audio signal made of a sine wave with amplitude 1/8. @@ -5939,7 +6314,7 @@ colorspace=smpte240m @section convolution -Apply convolution 3x3 or 5x5 filter. +Apply convolution 3x3, 5x5 or 7x7 filter. The filter accepts the following options: @@ -5949,7 +6324,7 @@ The filter accepts the following options: @item 2m @item 3m Set matrix for each plane. -Matrix is sequence of 9 or 25 signed integers. +Matrix is sequence of 9, 25 or 49 signed integers. @item 0rdiv @item 1rdiv @@ -6673,6 +7048,29 @@ Set whether or not chroma is considered in the metric calculations. Default is @code{1}. @end table +@section deconvolve + +Apply 2D deconvolution of video stream in frequency domain using second stream +as impulse. + +The filter accepts the following options: + +@table @option +@item planes +Set which planes to process. + +@item impulse +Set which impulse video frames will be processed, can be @var{first} +or @var{all}. Default is @var{all}. + +@item noise +Set noise when doing divisions. Default is @var{0.0000001}. Useful when width +and height are not same and not power of 2 or if stream prior to convolving +had noise. +@end table + +The @code{deconvolve} filter also supports the @ref{framesync} options. + @section deflate Apply deflate effect to the video. @@ -6887,10 +7285,6 @@ Default value is @samp{exhaustive}. If set then a detailed log of the motion search is written to the specified file. -@item opencl -If set to 1, specify using OpenCL capabilities, only available if -FFmpeg was configured with @code{--enable-opencl}. Default value is 0. - @end table @section despill @@ -7060,9 +7454,15 @@ value @code{invert} is used, the box edge color is the same as the video with inverted luma. @item thickness, t -The expression which sets the thickness of the box edge. Default value is @code{3}. +The expression which sets the thickness of the box edge. +A value of @code{fill} will create a filled box. Default value is @code{3}. See below for the list of accepted constants. + +@item replace +Applicable if the input has alpha. With value @code{1}, the pixels of the painted box +will overwrite the video's color and alpha pixels. +Default is @code{0}, which composites the box onto the input, leaving the video's alpha intact. @end table The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the @@ -7123,7 +7523,7 @@ drawbox=x=10:y=20:w=200:h=60:color=red@@0.5 @item Fill the box with pink color: @example -drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=max +drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=fill @end example @item @@ -7160,6 +7560,11 @@ video with inverted luma. The expression which sets the thickness of the grid line. Default value is @code{1}. See below for the list of accepted constants. + +@item replace +Applicable if the input has alpha. With @code{1} the pixels of the painted grid +will overwrite the video's color and alpha pixels. +Default is @code{0}, which composites the grid onto the input, leaving the video's alpha intact. @end table The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the @@ -7365,7 +7770,9 @@ format. It can be used with or without text parameter. @var{timecode_rate} option must be specified. @item timecode_rate, rate, r -Set the timecode frame rate (timecode only). +Set the timecode frame rate (timecode only). Value will be rounded to nearest +integer. Minimum value is "1". +Drop-frame timecode is supported for frame rates 30 & 60. @item tc24hmax If set to 1, the output of the timecode option will wrap around at 24 hours. @@ -7924,6 +8331,20 @@ Set pal8 output pixel format. This option does not work with codebook length greater than 256. @end table +@section entropy + +Measure graylevel entropy in histogram of color channels of video frames. + +It accepts the following parameters: + +@table @option +@item mode +Can be either @var{normal} or @var{diff}. Default is @var{normal}. + +@var{diff} mode measures entropy of histogram delta values, absolute differences +between neighbour histogram values. +@end table + @section fade Apply a fade-in/out effect to the input video. @@ -8525,6 +8946,48 @@ framework. It does not take parameters. +@section fillborders + +Fill borders of the input video, without changing video stream dimensions. +Sometimes video can have garbage at the four edges and you may not want to +crop video input to keep size multiple of some number. + +This filter accepts the following options: + +@table @option +@item left +Number of pixels to fill from left border. + +@item right +Number of pixels to fill from right border. + +@item top +Number of pixels to fill from top border. + +@item bottom +Number of pixels to fill from bottom border. + +@item mode +Set fill mode. + +It accepts the following values: +@table @samp +@item smear +fill pixels using outermost pixels + +@item mirror +fill pixels using mirroring + +@item fixed +fill pixels with constant value +@end table + +Default is @var{smear}. + +@item color +Set color for pixels in fixed mode. Default is @var{black}. +@end table + @section find_rect Find a rectangular object @@ -8806,7 +9269,7 @@ Specify the level at which a scene change is detected as a value between 0 and 100 to indicate a new scene; a low value reflects a low probability for the current frame to introduce a new scene, while a higher value means the current frame is more likely to be one. -The default is @code{7}. +The default is @code{8.2}. @item flags Specify flags influencing the filter process. @@ -9885,25 +10348,16 @@ distances from the focal point in the source and target images, respectively. @section libvmaf -Obtain the average VMAF (Video Multi-Method Assessment Fusion) +Obtain the VMAF (Video Multi-Method Assessment Fusion) score between two input videos. -This filter takes two input videos. - -Both video inputs must have the same resolution and pixel format for -this filter to work correctly. Also it assumes that both inputs -have the same number of frames, which are compared one by one. - -The obtained average VMAF score is printed through the logging system. +The obtained VMAF score is printed through the logging system. It requires Netflix's vmaf library (libvmaf) as a pre-requisite. After installing the library it can be enabled using: @code{./configure --enable-libvmaf}. If no model path is specified it uses the default model: @code{vmaf_v0.6.1.pkl}. -On the below examples the input file @file{main.mpg} being processed is -compared with the reference file @file{ref.mpg}. - The filter has following options: @table @option @@ -9934,12 +10388,14 @@ Enables computing ssim along with vmaf. Enables computing ms_ssim along with vmaf. @item pool -Set the pool method to be used for computing vmaf. +Set the pool method (mean, min or harmonic mean) to be used for computing vmaf. @end table This filter also supports the @ref{framesync} options. -For example: +On the below examples the input file @file{main.mpg} being processed is +compared with the reference file @file{ref.mpg}. + @example ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf -f null - @end example @@ -9974,13 +10430,14 @@ The filter accepts the following options: @table @option @item loop -Set the number of loops. +Set the number of loops. Setting this value to -1 will result in infinite loops. +Default is 0. @item size -Set maximal size in number of frames. +Set maximal size in number of frames. Default is 0. @item start -Set first frame of loop. +Set first frame of loop. Default is 0. @end table @anchor{lut3d} @@ -10550,6 +11007,34 @@ Default method is @samp{fdiff}. Scene change detection threshold. Default is @code{5.0}. @end table +@section mix + +Mix several video input streams into one video stream. + +A description of the accepted options follows. + +@table @option +@item nb_inputs +The number of inputs. If unspecified, it defaults to 2. + +@item weights +Specify weight of each input video stream as sequence. +Each weight is separated by space. + +@item duration +Specify how end of stream is determined. +@table @samp +@item longest +The duration of the longest input. (default) + +@item shortest +The duration of the shortest input. + +@item first +The duration of the first input. +@end table +@end table + @section mpdecimate Drop frames that do not differ greatly from the previous frame in @@ -10820,6 +11305,86 @@ Add temporal and uniform noise to input video: noise=alls=20:allf=t+u @end example +@section normalize + +Normalize RGB video (aka histogram stretching, contrast stretching). +See: https://en.wikipedia.org/wiki/Normalization_(image_processing) + +For each channel of each frame, the filter computes the input range and maps +it linearly to the user-specified output range. The output range defaults +to the full dynamic range from pure black to pure white. + +Temporal smoothing can be used on the input range to reduce flickering (rapid +changes in brightness) caused when small dark or bright objects enter or leave +the scene. This is similar to the auto-exposure (automatic gain control) on a +video camera, and, like a video camera, it may cause a period of over- or +under-exposure of the video. + +The R,G,B channels can be normalized independently, which may cause some +color shifting, or linked together as a single channel, which prevents +color shifting. Linked normalization preserves hue. Independent normalization +does not, so it can be used to remove some color casts. Independent and linked +normalization can be combined in any ratio. + +The normalize filter accepts the following options: + +@table @option +@item blackpt +@item whitept +Colors which define the output range. The minimum input value is mapped to +the @var{blackpt}. The maximum input value is mapped to the @var{whitept}. +The defaults are black and white respectively. Specifying white for +@var{blackpt} and black for @var{whitept} will give color-inverted, +normalized video. Shades of grey can be used to reduce the dynamic range +(contrast). Specifying saturated colors here can create some interesting +effects. + +@item smoothing +The number of previous frames to use for temporal smoothing. The input range +of each channel is smoothed using a rolling average over the current frame +and the @var{smoothing} previous frames. The default is 0 (no temporal +smoothing). + +@item independence +Controls the ratio of independent (color shifting) channel normalization to +linked (color preserving) normalization. 0.0 is fully linked, 1.0 is fully +independent. Defaults to 1.0 (fully independent). + +@item strength +Overall strength of the filter. 1.0 is full strength. 0.0 is a rather +expensive no-op. Defaults to 1.0 (full strength). + +@end table + +@subsection Examples + +Stretch video contrast to use the full dynamic range, with no temporal +smoothing; may flicker depending on the source content: +@example +normalize=blackpt=black:whitept=white:smoothing=0 +@end example + +As above, but with 50 frames of temporal smoothing; flicker should be +reduced, depending on the source content: +@example +normalize=blackpt=black:whitept=white:smoothing=50 +@end example + +As above, but with hue-preserving linked channel normalization: +@example +normalize=blackpt=black:whitept=white:smoothing=50:independence=0 +@end example + +As above, but with half strength: +@example +normalize=blackpt=black:whitept=white:smoothing=50:independence=0:strength=0.5 +@end example + +Map the darkest input color to red, the brightest input color to cyan: +@example +normalize=blackpt=red:whitept=cyan +@end example + @section null Pass the video source unchanged to the output. @@ -11099,6 +11664,10 @@ Default value is @samp{yuv420}. @item repeatlast See @ref{framesync}. + +@item alpha +Set format of alpha of the overlaid video, it can be @var{straight} or +@var{premultiplied}. Default is @var{straight}. @end table The @option{x}, and @option{y} expressions can contain the following @@ -11458,6 +12027,9 @@ If not set, the maximum of colors in the palette will be 256. You probably want to disable this option for a standalone image. Set by default. +@item transparency_color +Set the color that will be used as background for transparency. + @item stats_mode Set statistics mode. @@ -11545,6 +12117,13 @@ Default is @var{none}. @item new Take new palette for each output frame. + +@item alpha_threshold +Sets the alpha threshold for transparency. Alpha values above this threshold +will be treated as completely opaque, and values below this threshold will be +treated as completely transparent. + +The option must be an integer value in the range [0,255]. Default is @var{128}. @end table @subsection Examples @@ -11974,6 +12553,136 @@ Set value which will be multiplied with filtered result. Set value which will be added to filtered result. @end table +@anchor{program_opencl} +@section program_opencl + +Filter video using an OpenCL program. + +@table @option + +@item source +OpenCL program source file. + +@item kernel +Kernel name in program. + +@item inputs +Number of inputs to the filter. Defaults to 1. + +@item size, s +Size of output frames. Defaults to the same as the first input. + +@end table + +The program source file must contain a kernel function with the given name, +which will be run once for each plane of the output. Each run on a plane +gets enqueued as a separate 2D global NDRange with one work-item for each +pixel to be generated. The global ID offset for each work-item is therefore +the coordinates of a pixel in the destination image. + +The kernel function needs to take the following arguments: +@itemize +@item +Destination image, @var{__write_only image2d_t}. + +This image will become the output; the kernel should write all of it. +@item +Frame index, @var{unsigned int}. + +This is a counter starting from zero and increasing by one for each frame. +@item +Source images, @var{__read_only image2d_t}. + +These are the most recent images on each input. The kernel may read from +them to generate the output, but they can't be written to. +@end itemize + +Example programs: + +@itemize +@item +Copy the input to the output (output must be the same size as the input). +@verbatim +__kernel void copy(__write_only image2d_t destination, + unsigned int index, + __read_only image2d_t source) +{ + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE; + + int2 location = (int2)(get_global_id(0), get_global_id(1)); + + float4 value = read_imagef(source, sampler, location); + + write_imagef(destination, location, value); +} +@end verbatim + +@item +Apply a simple transformation, rotating the input by an amount increasing +with the index counter. Pixel values are linearly interpolated by the +sampler, and the output need not have the same dimensions as the input. +@verbatim +__kernel void rotate_image(__write_only image2d_t dst, + unsigned int index, + __read_only image2d_t src) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_LINEAR); + + float angle = (float)index / 100.0f; + + float2 dst_dim = convert_float2(get_image_dim(dst)); + float2 src_dim = convert_float2(get_image_dim(src)); + + float2 dst_cen = dst_dim / 2.0f; + float2 src_cen = src_dim / 2.0f; + + int2 dst_loc = (int2)(get_global_id(0), get_global_id(1)); + + float2 dst_pos = convert_float2(dst_loc) - dst_cen; + float2 src_pos = { + cos(angle) * dst_pos.x - sin(angle) * dst_pos.y, + sin(angle) * dst_pos.x + cos(angle) * dst_pos.y + }; + src_pos = src_pos * src_dim / dst_dim; + + float2 src_loc = src_pos + src_cen; + + if (src_loc.x < 0.0f || src_loc.y < 0.0f || + src_loc.x > src_dim.x || src_loc.y > src_dim.y) + write_imagef(dst, dst_loc, 0.5f); + else + write_imagef(dst, dst_loc, read_imagef(src, sampler, src_loc)); +} +@end verbatim + +@item +Blend two inputs together, with the amount of each input used varying +with the index counter. +@verbatim +__kernel void blend_images(__write_only image2d_t dst, + unsigned int index, + __read_only image2d_t src1, + __read_only image2d_t src2) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_LINEAR); + + float blend = (cos((float)index / 50.0f) + 1.0f) / 2.0f; + + int2 dst_loc = (int2)(get_global_id(0), get_global_id(1)); + int2 src1_loc = dst_loc * get_image_dim(src1) / get_image_dim(dst); + int2 src2_loc = dst_loc * get_image_dim(src2) / get_image_dim(dst); + + float4 val1 = read_imagef(src1, sampler, src1_loc); + float4 val2 = read_imagef(src2, sampler, src2_loc); + + write_imagef(dst, dst_loc, val1 * blend + val2 * (1.0f - blend)); +} +@end verbatim + +@end itemize + @section pseudocolor Alter frame colors in video with pseudocolors. @@ -12105,7 +12814,7 @@ sequential number of the input frame, starting from 1 Mean Square Error pixel-by-pixel average difference of the compared frames, averaged over all the image components. -@item mse_y, mse_u, mse_v, mse_r, mse_g, mse_g, mse_a +@item mse_y, mse_u, mse_v, mse_r, mse_g, mse_b, mse_a Mean Square Error pixel-by-pixel average difference of the compared frames for the component specified by the suffix. @@ -12847,13 +13556,13 @@ a specific value used for the output and encoder. If not specified, the range depends on the pixel format. Possible values: @table @samp -@item auto +@item auto/unknown Choose automatically. @item jpeg/full/pc Set full range (0-255 in case of 8-bit luma). -@item mpeg/tv +@item mpeg/limited/tv Set "MPEG" range (16-235 in case of 8-bit luma). @end table @@ -14436,6 +15145,15 @@ refer to the pad video filter. Specify the color of the unused area. For the syntax of this option, check the "Color" section in the ffmpeg-utils manual. The default value of @var{color} is "black". + +@item overlap +Set the number of frames to overlap when tiling several successive frames together. +The value must be between @code{0} and @var{nb_frames - 1}. + +@item init_padding +Set the number of frames to initially be empty before displaying first output frame. +This controls how soon will one get first output frame. +The value must be between @code{0} and @var{nb_frames - 1}. @end table @subsection Examples @@ -15013,10 +15731,6 @@ sharpen it, a value of zero will disable the effect. Default value is 0.0. -@item opencl -If set to 1, specify using OpenCL capabilities, only available if -FFmpeg was configured with @code{--enable-opencl}. Default value is 0. - @end table All parameters are optional and default to the equivalent of the @@ -16855,28 +17569,24 @@ The sources accept the following parameters: @table @option -@item alpha -Specify the alpha (opacity) of the background, only available in the -@code{testsrc2} source. The value must be between 0 (fully transparent) and -255 (fully opaque, the default). - -@item color, c -Specify the color of the source, only available in the @code{color} -source. For the syntax of this option, check the "Color" section in the -ffmpeg-utils manual. - @item level Specify the level of the Hald CLUT, only available in the @code{haldclutsrc} source. A level of @code{N} generates a picture of @code{N*N*N} by @code{N*N*N} pixels to be used as identity matrix for 3D lookup tables. Each component is coded on a @code{1/(N*N)} scale. +@item color, c +Specify the color of the source, only available in the @code{color} +source. For the syntax of this option, check the "Color" section in the +ffmpeg-utils manual. + @item size, s Specify the size of the sourced video. For the syntax of this option, check the @ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}. The default value is @code{320x240}. -This option is not available with the @code{haldclutsrc} filter. +This option is not available with the @code{allrgb}, @code{allyuv}, and +@code{haldclutsrc} filters. @item rate, r Specify the frame rate of the sourced video, as the number of frames @@ -16885,9 +17595,6 @@ generated per second. It has to be a string in the format number or a valid video frame rate abbreviation. The default value is "25". -@item sar -Set the sample aspect ratio of the sourced video. - @item duration, d Set the duration of the sourced video. See @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} @@ -16896,6 +17603,14 @@ for the accepted syntax. If not specified, or the expressed duration is negative, the video is supposed to be generated forever. +@item sar +Set the sample aspect ratio of the sourced video. + +@item alpha +Specify the alpha (opacity) of the background, only available in the +@code{testsrc2} source. The value must be between 0 (fully transparent) and +255 (fully opaque, the default). + @item decimals, n Set the number of decimals to show in the timestamp, only available in the @code{testsrc} source. @@ -16905,27 +17620,32 @@ timestamp value multiplied by the power of 10 of the specified value. Default value is 0. @end table -For example the following: +@subsection Examples + +@itemize +@item +Generate a video with a duration of 5.3 seconds, with size +176x144 and a frame rate of 10 frames per second: @example testsrc=duration=5.3:size=qcif:rate=10 @end example -will generate a video with a duration of 5.3 seconds, with size -176x144 and a frame rate of 10 frames per second. - +@item The following graph description will generate a red source with an opacity of 0.2, with size "qcif" and a frame rate of 10 -frames per second. +frames per second: @example color=c=red@@0.2:s=qcif:r=10 @end example +@item If the input content is to be ignored, @code{nullsrc} can be used. The following command generates noise in the luminance plane by employing the @code{geq} filter: @example nullsrc=s=256x256, geq=random(1)*255:128:128 @end example +@end itemize @subsection Commands @@ -16937,6 +17657,78 @@ Set the color of the created image. Accepts the same syntax of the corresponding @option{color} option. @end table +@section openclsrc + +Generate video using an OpenCL program. + +@table @option + +@item source +OpenCL program source file. + +@item kernel +Kernel name in program. + +@item size, s +Size of frames to generate. This must be set. + +@item format +Pixel format to use for the generated frames. This must be set. + +@item rate, r +Number of frames generated every second. Default value is '25'. + +@end table + +For details of how the program loading works, see the @ref{program_opencl} +filter. + +Example programs: + +@itemize +@item +Generate a colour ramp by setting pixel values from the position of the pixel +in the output image. (Note that this will work with all pixel formats, but +the generated output will not be the same.) +@verbatim +__kernel void ramp(__write_only image2d_t dst, + unsigned int index) +{ + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 val; + val.xy = val.zw = convert_float2(loc) / convert_float2(get_image_dim(dst)); + + write_imagef(dst, loc, val); +} +@end verbatim + +@item +Generate a Sierpinski carpet pattern, panning by a single pixel each frame. +@verbatim +__kernel void sierpinski_carpet(__write_only image2d_t dst, + unsigned int index) +{ + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 value = 0.0f; + int x = loc.x + index; + int y = loc.y + index; + while (x > 0 || y > 0) { + if (x % 3 == 1 && y % 3 == 1) { + value = 1.0f; + break; + } + x /= 3; + y /= 3; + } + + write_imagef(dst, loc, value); +} +@end verbatim + +@end itemize + @c man end VIDEO SOURCES @chapter Video Sinks @@ -17197,6 +17989,26 @@ Cubic root. Logarithmic. @end table +@item swap +Swap left channel axis with right channel axis. + +@item mirror +Mirror axis. + +@table @samp +@item none +No mirror. + +@item x +Mirror only x axis. + +@item y +Mirror only y axis. + +@item xy +Mirror both axis. +@end table + @end table @subsection Examples @@ -17679,7 +18491,7 @@ with AV_LOG_INFO loglevel. @itemize @item -Print all metadata values for frames with key @code{lavfi.singnalstats.YDIF} with values +Print all metadata values for frames with key @code{lavfi.signalstats.YDIF} with values between 0 and 1. @example signalstats,metadata=print:key=lavfi.signalstats.YDIF:value=0:function=expr:expr='between(VALUE1,0,1)' @@ -17807,7 +18619,7 @@ The PTS of the previously filtered video frame. It's NAN if undefined. The PTS of the last previously filtered video frame. It's NAN if undefined. @item prev_selected_t -The PTS of the last previously selected video frame. It's NAN if undefined. +The PTS of the last previously selected video frame, expressed in seconds. It's NAN if undefined. @item start_pts The PTS of the first video frame in the video. It's NAN if undefined. @@ -18232,6 +19044,37 @@ asetpts=N/SR/TB @end itemize +@section setrange + +Force color range for the output video frame. + +The @code{setrange} filter marks the color range property for the +output frames. It does not change the input frame, but only sets the +corresponding property, which affects how the frame is treated by +following filters. + +The filter accepts the following options: + +@table @option + +@item range +Available values are: + +@table @samp +@item auto +Keep the same color range property. + +@item unspecified, unknown +Set the color range as unspecified. + +@item limited, tv, mpeg +Set the color range as limited. + +@item full, pc, jpeg +Set the color range as full. +@end table +@end table + @section settb, asettb Set the timebase to use for the output frames timestamps. diff --git a/doc/general.texi b/doc/general.texi index a40400612..26919c928 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -365,6 +365,7 @@ library: @item Interplay MVE @tab @tab X @tab Format used in various Interplay computer games. @item Iterated Systems ClearVideo @tab @tab X + @tab I-frames only @item IV8 @tab @tab X @tab A format generated by IndigoVision 8000 video server. @item IVF (On2) @tab X @tab X @@ -424,6 +425,7 @@ library: @item NC camera feed @tab @tab X @tab NC (AVIP NC4600) camera streams @item NIST SPeech HEader REsources @tab @tab X +@item Computerized Speech Lab NSP @tab @tab X @item NTT TwinVQ (VQF) @tab @tab X @tab Nippon Telegraph and Telephone Corporation TwinVQ. @item Nullsoft Streaming Video @tab @tab X @@ -438,6 +440,9 @@ library: @item QCP @tab @tab X @item raw ADTS (AAC) @tab X @tab X @item raw AC-3 @tab X @tab X +@item raw AMR-NB @tab @tab X +@item raw AMR-WB @tab @tab X +@item raw aptX @tab X @tab X @item raw Chinese AVS video @tab X @tab X @item raw CRI ADX @tab X @tab X @item raw Dirac @tab X @tab X @@ -792,7 +797,7 @@ following image formats are supported: @item LucasArts SANM/Smush @tab @tab X @tab Used in LucasArts games / SMUSH animations. @item lossless MJPEG @tab X @tab X -@item MagicYUV Video @tab @tab X +@item MagicYUV Video @tab X @tab X @item Mandsoft Screen Capture Codec @tab @tab X @item Microsoft ATC Screen @tab @tab X @tab Also known as Microsoft Screen 3. @@ -990,6 +995,8 @@ following image formats are supported: @item Amazing Studio PAF Audio @tab @tab X @item Apple lossless audio @tab X @tab X @tab QuickTime fourcc 'alac' +@item aptX @tab X @tab X + @tab Used in Bluetooth A2DP @item ATRAC1 @tab @tab X @item ATRAC3 @tab @tab X @item ATRAC3+ @tab @tab X diff --git a/doc/indevs.texi b/doc/indevs.texi index 55a4084bb..56066bf23 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -238,6 +238,8 @@ This sets the input video format to the format given by the FourCC. To see the supported values of your device(s) use @option{list_formats}. Note that there is a FourCC @option{'pal '} that can also be used as @option{pal} (3 letters). +Default behavior is autodetection of the input video format, if the hardware +supports it. @item bm_v210 This is a deprecated option, you can use @option{raw_format} instead. @@ -311,6 +313,10 @@ Sets maximum input buffer size in bytes. If the buffering reaches this value, incoming frames will be dropped. Defaults to @samp{1073741824}. +@item audio_depth +Sets the audio sample bit depth. Must be @samp{16} or @samp{32}. +Defaults to @samp{16}. + @end table @subsection Examples diff --git a/doc/issue_tracker.txt b/doc/issue_tracker.txt index e8e85304b..5d9805a4b 100644 --- a/doc/issue_tracker.txt +++ b/doc/issue_tracker.txt @@ -193,9 +193,6 @@ ffplay ffprobe issues in or related to ffprobe.c -ffserver - issues in or related to ffserver.c - postproc issues in libpostproc/* diff --git a/doc/libav-merge.txt b/doc/libav-merge.txt index 4a46bfcf4..4ba08fc58 100644 --- a/doc/libav-merge.txt +++ b/doc/libav-merge.txt @@ -94,13 +94,13 @@ Stuff that didn't reach the codebase: - a853388d2 hevc: change the stride of the MC buffer to be in bytes instead of elements - 0cef06df0 checkasm: add HEVC MC tests - e7078e842 hevcdsp: add x86 SIMD for MC -- VAAPI VP8 decode hwaccel (currently under review: http://ffmpeg.org/pipermail/ffmpeg-devel/2017-February/thread.html#207348) -- Removal of the custom atomic API (5cc0057f49, see http://ffmpeg.org/pipermail/ffmpeg-devel/2017-March/209003.html) + - 7993ec19a hevc: Add hevc_get_pixel_4/8/12/16/24/32/48/64 - new bitstream reader (see http://ffmpeg.org/pipermail/ffmpeg-devel/2017-April/209609.html) -- use of the bsf instead of our parser for vp9 superframes (see fa1749dd34) - use av_cpu_max_align() instead of hardcoding alignment requirements (see https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/215834.html) - f44ec22e0 lavc: use av_cpu_max_align() instead of hardcoding alignment requirements - 4de220d2e frame: allow align=0 (meaning automatic) for av_frame_get_buffer() +- Support recovery from an already present HLS playlist (see 16cb06bb30) +- Remove all output devices (see 8e7e042d41, 8d3db95f20, 6ce13070bd, d46cd24986 and https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/216904.html) Collateral damage that needs work locally: ------------------------------------------ diff --git a/doc/libavcodec.texi b/doc/libavcodec.texi index 87b90db48..b22c47ae8 100644 --- a/doc/libavcodec.texi +++ b/doc/libavcodec.texi @@ -26,13 +26,13 @@ implementing robust and fast codecs as well as for experimentation. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-codecs.html,ffmpeg-codecs}, @url{ffmpeg-bitstream-filters.html,bitstream-filters}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), libavutil(3) @end ifnothtml diff --git a/doc/libavdevice.texi b/doc/libavdevice.texi index 9b10282cd..0abdaaff0 100644 --- a/doc/libavdevice.texi +++ b/doc/libavdevice.texi @@ -23,13 +23,13 @@ VfW, DShow, and ALSA. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-devices.html,ffmpeg-devices}, @url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-devices(1), libavutil(3), libavcodec(3), libavformat(3) @end ifnothtml diff --git a/doc/libavfilter.texi b/doc/libavfilter.texi index 52e075369..d9472eb0a 100644 --- a/doc/libavfilter.texi +++ b/doc/libavfilter.texi @@ -21,14 +21,14 @@ framework containing several filters, sources and sinks. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-filters.html,ffmpeg-filters}, @url{libavutil.html,libavutil}, @url{libswscale.html,libswscale}, @url{libswresample.html,libswresample}, @url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat}, @url{libavdevice.html,libavdevice} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-filters(1), libavutil(3), libswscale(3), libswresample(3), libavcodec(3), libavformat(3), libavdevice(3) @end ifnothtml diff --git a/doc/libavformat.texi b/doc/libavformat.texi index d505d644f..7cf41fdfd 100644 --- a/doc/libavformat.texi +++ b/doc/libavformat.texi @@ -26,13 +26,13 @@ resource. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-formats.html,ffmpeg-formats}, @url{ffmpeg-protocols.html,ffmpeg-protocols}, @url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-formats(1), ffmpeg-protocols(1), libavutil(3), libavcodec(3) @end ifnothtml diff --git a/doc/libavutil.texi b/doc/libavutil.texi index 7a1c332b8..ee50362f6 100644 --- a/doc/libavutil.texi +++ b/doc/libavutil.texi @@ -42,12 +42,12 @@ It should avoid useless features that almost no one needs. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-utils.html,ffmpeg-utils} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-utils(1) @end ifnothtml diff --git a/doc/libswresample.texi b/doc/libswresample.texi index bb5727831..3108cb1ba 100644 --- a/doc/libswresample.texi +++ b/doc/libswresample.texi @@ -48,13 +48,13 @@ enabled through dedicated options. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-resampler(1), libavutil(3) @end ifnothtml diff --git a/doc/libswscale.texi b/doc/libswscale.texi index 757fd2413..e137c24a4 100644 --- a/doc/libswscale.texi +++ b/doc/libswscale.texi @@ -41,13 +41,13 @@ colorspaces differ. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-scaler(1), libavutil(3) @end ifnothtml diff --git a/doc/mailing-list-faq.texi b/doc/mailing-list-faq.texi index fe2171e42..9af89815d 100644 --- a/doc/mailing-list-faq.texi +++ b/doc/mailing-list-faq.texi @@ -27,8 +27,7 @@ for examples. @item @url{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-user/, ffmpeg-user}: For questions involving unscripted usage or compilation of the FFmpeg -command-line tools (@command{ffmpeg}, @command{ffprobe}, @command{ffplay}, -@command{ffserver}). +command-line tools (@command{ffmpeg}, @command{ffprobe}, @command{ffplay}). @item @url{https://lists.ffmpeg.org/mailman/listinfo/libav-user/, libav-user}: diff --git a/doc/muxers.texi b/doc/muxers.texi index 91bbe673c..b060c4f36 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -247,6 +247,13 @@ DASH-templated name to used for the initialization segment. Default is "init-str DASH-templated name to used for the media segments. Default is "chunk-stream$RepresentationID$-$Number%05d$.m4s" @item -utc_timing_url @var{utc_url} URL of the page that will return the UTC timestamp in ISO format. Example: "https://time.akamai.com/?iso" +@item -http_user_agent @var{user_agent} +Override User-Agent field in HTTP header. Applicable only for HTTP output. +@item -http_persistent @var{http_persistent} +Use persistent HTTP connections. Applicable only for HTTP output. +@item -hls_playlist @var{hls_playlist} +Generate HLS playlist files as well. The master playlist is generated with the filename master.m3u8. +One media playlist file is generated for each stream with filenames media_0.m3u8, media_1.m3u8, etc. @item -adaptation_sets @var{adaptation_sets} Assign streams to AdaptationSets. Syntax is "id=x,streams=a,b,c id=y,streams=d,e" with x and y being the IDs of the adaptation sets and a,b,c,d and e are the indices of the mapped streams. @@ -468,9 +475,12 @@ By default, the muxer creates a file for each segment produced. These files have the same name as the playlist, followed by a sequential number and a .ts extension. +Make sure to require a closed GOP when encoding and to set the GOP +size to fit your segment time constraint. + For example, to convert an input file with @command{ffmpeg}: @example -ffmpeg -i in.nut out.m3u8 +ffmpeg -i in.mkv -c:v h264 -flags +cgop -g 30 -hls_time 1 out.m3u8 @end example This example will produce the playlist, @file{out.m3u8}, and segment files: @file{out0.ts}, @file{out1.ts}, @file{out2.ts}, etc. @@ -567,6 +577,31 @@ Should a relative path be specified, the path of the created segment files will be relative to the current working directory. When use_localtime_mkdir is set, the whole expanded value of @var{filename} will be written into the m3u8 segment list. +When @code{var_stream_map} is set with two or more variant streams, the +@var{filename} pattern must contain the string "%v", this string specifies +the position of variant stream index in the generated segment file names. +@example +ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + -hls_segment_filename 'file_%v_%03d.ts' out_%v.m3u8 +@end example +This example will produce the playlists segment file sets: +@file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and +@file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc. + +The string "%v" may be present in the filename or in the last directory name +containing the file. If the string is present in the directory name, then +sub-directories are created after expanding the directory name pattern. This +enables creation of segments corresponding to different variant streams in +subdirectories. +@example +ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + -hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8 +@end example +This example will produce the playlists segment file sets: +@file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. and +@file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc. @item use_localtime Use strftime() on @var{filename} to expand the segment filename with localtime. @@ -693,6 +728,15 @@ the fmp4 files is used in hls after version 7. @item hls_fmp4_init_filename @var{filename} set filename to the fragment files header file, default filename is @file{init.mp4}. +When @code{var_stream_map} is set with two or more variant streams, the +@var{filename} pattern must contain the string "%v", this string specifies +the position of variant stream index in the generated init file names. +The string "%v" may be present in the filename or in the last directory name +containing the file. If the string is present in the directory name, then +sub-directories are created after expanding the directory name pattern. This +enables creation of init files corresponding to different variant streams in +subdirectories. + @item hls_flags @var{flags} Possible values: @@ -732,6 +776,10 @@ The file specified by @code{hls_key_info_file} will be checked periodically and detect updates to the encryption info. Be sure to replace this file atomically, including the file containing the AES encryption key. +@item independent_segments +Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} to playlists that has video segments +and when all the segments of that playlist are guaranteed to start with a Key frame. + @item split_by_time Allow segments to start on frames other than keyframes. This improves behavior on some players when the time between keyframes is inconsistent, @@ -794,6 +842,88 @@ files. @item http_user_agent Override User-Agent field in HTTP header. Applicable only for HTTP output. +@item var_stream_map +Map string which specifies how to group the audio, video and subtitle streams +into different variant streams. The variant stream groups are separated +by space. +Expected string format is like this "a:0,v:0 a:1,v:1 ....". Here a:, v:, s: are +the keys to specify audio, video and subtitle streams respectively. +Allowed values are 0 to 9 (limited just based on practical usage). + +When there are two or more variant streams, the output filename pattern must +contain the string "%v", this string specifies the position of variant stream +index in the output media playlist filenames. The string "%v" may be present in +the filename or in the last directory name containing the file. If the string is +present in the directory name, then sub-directories are created after expanding +the directory name pattern. This enables creation of variant streams in +subdirectories. + +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates two hls variant streams. The first variant stream will +contain video stream of bitrate 1000k and audio stream of bitrate 64k and the +second variant stream will contain video stream of bitrate 256k and audio +stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and +out_1.m3u8 will be created. +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \ + -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates three hls variant streams. The first variant stream will +be a video only stream with video bitrate 1000k, the second variant stream will +be an audio only stream with bitrate 64k and the third variant stream will be a +video only stream with bitrate 256k. Here, three media playlist with file names +out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created. +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + http://example.com/live/vs_%v/out.m3u8 +@end example +This example creates the variant streams in subdirectories. Here, the first +media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and +the second one at @file{http://example.com/live/vs_1/out.m3u8}. +@example +ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k \ + -map 0:a -map 0:a -map 0:v -map 0:v -f hls \ + -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low v:1,agroup:aud_high" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates two audio only and two video only variant streams. In +addition to the #EXT-X-STREAM-INF tag for each variant stream in the master +playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams +and they are mapped to the two video only variant streams with audio group names +'aud_low' and 'aud_high'. + +By default, a single hls variant containing all the encoded streams is created. + +@item master_pl_name +Create HLS master playlist with the given name. + +@example +ffmpeg -re -i in.ts -f hls -master_pl_name master.m3u8 http://example.com/live/out.m3u8 +@end example +This example creates HLS master playlist with name master.m3u8 and it is +published at http://example.com/live/ + +@item master_pl_publish_rate +Publish master play list repeatedly every after specified number of segment intervals. + +@example +ffmpeg -re -i in.ts -f hls -master_pl_name master.m3u8 \ +-hls_time 2 -master_pl_publish_rate 30 http://example.com/live/out.m3u8 +@end example + +This example creates HLS master playlist with name master.m3u8 and keep +publishing it repeatedly every after 30 segments i.e. every after 60s. + +@item http_persistent +Use persistent HTTP connections. Applicable only for HTTP output. + @end table @anchor{ico} @@ -894,9 +1024,18 @@ can be used: ffmpeg -f v4l2 -r 1 -i /dev/video0 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S.jpg" @end example +You can set the file name with current frame's PTS: +@example +ffmpeg -f v4l2 -r 1 -i /dev/video0 -copyts -f image2 -frame_pts true %d.jpg" +@end example + @subsection Options @table @option +@item frame_pts +If set to 1, expand the filename with pts from pkt->pts. +Default value is 0. + @item start_number Start the sequence from the specified number. Default value is 1. @@ -1649,6 +1788,9 @@ segment would usually span. Otherwise, the segment will be filled with the next packet written. Defaults to @code{0}. @end table +Make sure to require a closed GOP when encoding and to set the GOP +size to fit your segment time constraint. + @subsection Examples @itemize @@ -1657,7 +1799,7 @@ Remux the content of file @file{in.mkv} to a list of segments @file{out-000.nut}, @file{out-001.nut}, etc., and write the list of generated segments to @file{out.list}: @example -ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.list out%03d.nut +ffmpeg -i in.mkv -codec hevc -flags +cgop -g 60 -map 0 -f segment -segment_list out.list out%03d.nut @end example @item diff --git a/doc/protocols.texi b/doc/protocols.texi index a7968ff56..98deb7300 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -321,6 +321,9 @@ Sets the maximum delay in seconds after which to give up reconnecting @item mime_type Export the MIME type. +@item http_version +Exports the HTTP response version number. Usually "1.0" or "1.1". + @item icy If set to 1 request ICY (SHOUTcast) metadata from the server. If the server supports this, the metadata has to be retrieved by the application by reading @@ -363,7 +366,7 @@ If set to 1 enables experimental HTTP server. This can be used to send data when used as an output option, or read data from a client with HTTP POST when used as an input option. If set to 2 enables experimental multi-client HTTP server. This is not yet implemented -in ffmpeg.c or ffserver.c and thus must not be used as a command line option. +in ffmpeg.c and thus must not be used as a command line option. @example # Server side (sending): ffmpeg -i somefile.ogg -c copy -listen 1 -f ogg http://@var{server}:@var{port} @@ -1186,6 +1189,7 @@ Accepted options: Start offset of the extracted segment, in bytes. @item end End offset of the extracted segment, in bytes. +If set to 0, extract till end of file. @end table Examples: @@ -1201,6 +1205,11 @@ Play an AVI file directly from a TAR archive: subfile,,start,183241728,end,366490624,,:archive.tar @end example +Play a MPEG-TS file from start offset till end: +@example +subfile,,start,32815239,end,0,,:video.ts +@end example + @section tee Writes the output to multiple protocols. The individual outputs are separated @@ -1242,6 +1251,9 @@ Set receive buffer size, expressed bytes. @item send_buffer_size=@var{bytes} Set send buffer size, expressed bytes. + +@item tcp_nodelay=@var{1|0} +Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0. @end table The following example shows how to setup a listening TCP connection @@ -1277,7 +1289,7 @@ If enabled, try to verify the peer that we are communicating with. Note, if using OpenSSL, this currently only makes sure that the peer certificate is signed by one of the root certificates in the CA database, but it does not validate that the certificate actually -matches the host name we are trying to connect to. (With GnuTLS, +matches the host name we are trying to connect to. (With other backends, the host name is validated as well.) This is disabled by default since it requires a CA database to be diff --git a/doc/utils.texi b/doc/utils.texi index e63511856..d55dd315c 100644 --- a/doc/utils.texi +++ b/doc/utils.texi @@ -1057,33 +1057,3 @@ indication of the corresponding powers of 10 and of 2. @end table @c man end EXPRESSION EVALUATION - -@chapter OpenCL Options -@c man begin OPENCL OPTIONS - -When FFmpeg is configured with @code{--enable-opencl}, it is possible -to set the options for the global OpenCL context. - -The list of supported options follows: - -@table @option -@item build_options -Set build options used to compile the registered kernels. - -See reference "OpenCL Specification Version: 1.2 chapter 5.6.4". - -@item platform_idx -Select the index of the platform to run OpenCL code. - -The specified index must be one of the indexes in the device list -which can be obtained with @code{ffmpeg -opencl_bench} or @code{av_opencl_get_device_list()}. - -@item device_idx -Select the index of the device used to run OpenCL code. - -The specified index must be one of the indexes in the device list which -can be obtained with @code{ffmpeg -opencl_bench} or @code{av_opencl_get_device_list()}. - -@end table - -@c man end OPENCL OPTIONS diff --git a/ffbuild/.gitignore b/ffbuild/.gitignore new file mode 100644 index 000000000..38ed17075 --- /dev/null +++ b/ffbuild/.gitignore @@ -0,0 +1,5 @@ +/.config +/config.fate +/config.log +/config.mak +/config.sh diff --git a/ffbuild/common.mak b/ffbuild/common.mak index e168fb2cf..eb41b05ee 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -119,7 +119,7 @@ FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS) TESTPROGS += $(TESTPROGS-yes) LDLIBS = $(FFLIBS:%=%$(BUILDSUF)) -FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS) +FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=EXTRALIBS-%),$($(lib))) $(EXTRALIBS) OBJS := $(sort $(OBJS:%=$(SUBDIR)%)) SLIBOBJS := $(sort $(SLIBOBJS:%=$(SUBDIR)%)) @@ -163,8 +163,7 @@ $(TOOLOBJS): | tools OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS)) -CLEANSUFFIXES = *.d *.o *~ *.h.c *.gcda *.gcno *.map *.ver *.version *.ho *$(DEFAULT_X86ASMD).asm *.ptx *.ptx.c -DISTCLEANSUFFIXES = *.pc +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 diff --git a/ffbuild/library.mak b/ffbuild/library.mak index 4191edcf9..612bacb98 100644 --- a/ffbuild/library.mak +++ b/ffbuild/library.mak @@ -1,6 +1,6 @@ include $(SRC_PATH)/ffbuild/common.mak -ifeq (,$(filter %clean,$(MAKECMDGOALS))) +ifeq (,$(filter %clean config,$(MAKECMDGOALS))) -include $(SUBDIR)lib$(NAME).version endif @@ -31,13 +31,15 @@ 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) $$(ELIBS) + $$(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 | $(SUBDIR) +$(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) @@ -48,7 +50,7 @@ $(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR) $(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver $(SLIB_CREATE_DEF_CMD) - $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDLIBFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) + $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) $(SLIB_EXTRA_CMD) ifdef SUBDIR @@ -59,10 +61,6 @@ clean:: $(RM) $(addprefix $(SUBDIR),$(CLEANFILES) $(CLEANSUFFIXES) $(LIBSUFFIXES)) \ $(CLEANSUFFIXES:%=$(SUBDIR)$(ARCH)/%) $(CLEANSUFFIXES:%=$(SUBDIR)tests/%) -distclean:: clean - $(RM) $(DISTCLEANSUFFIXES:%=$(SUBDIR)%) $(DISTCLEANSUFFIXES:%=$(SUBDIR)$(ARCH)/%) \ - $(DISTCLEANSUFFIXES:%=$(SUBDIR)tests/%) - install-lib$(NAME)-shared: $(SUBDIR)$(SLIBNAME) $(Q)mkdir -p "$(SHLIBDIR)" $$(INSTALL) -m 755 $$< "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)" @@ -95,8 +93,10 @@ uninstall-libs:: uninstall-headers:: $(RM) $(addprefix "$(INCINSTDIR)/",$(HEADERS) $(BUILT_HEADERS)) - $(RM) "$(PKGCONFIGDIR)/lib$(FULLNAME).pc" -rmdir "$(INCINSTDIR)" + +uninstall-pkgconfig:: + $(RM) "$(PKGCONFIGDIR)/lib$(FULLNAME).pc" endef $(eval $(RULES)) diff --git a/fftools/Makefile b/fftools/Makefile index c867814a7..c3a0ff340 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -1,12 +1,11 @@ AVPROGS-$(CONFIG_FFMPEG) += ffmpeg AVPROGS-$(CONFIG_FFPLAY) += ffplay AVPROGS-$(CONFIG_FFPROBE) += ffprobe -AVPROGS-$(CONFIG_FFSERVER) += ffserver AVPROGS := $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF)) PROGS += $(AVPROGS) -AVBASENAMES = ffmpeg ffplay ffprobe ffserver +AVBASENAMES = ffmpeg ffplay ffprobe ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF)) ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF)) @@ -17,7 +16,6 @@ ifndef CONFIG_VIDEOTOOLBOX OBJS-ffmpeg-$(CONFIG_VDA) += fftools/ffmpeg_videotoolbox.o endif OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += fftools/ffmpeg_videotoolbox.o -OBJS-ffserver += fftools/ffserver_config.o define DOFFTOOL OBJS-$(1) += fftools/cmdutils.o fftools/$(1).o $(OBJS-$(1)-yes) @@ -29,7 +27,6 @@ $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1)) -include $$(OBJS-$(1):.o=.d) endef -$(foreach P,$(AVPROGS-yes),$(eval OBJS-$(P)-$(CONFIG_OPENCL) += fftools/cmdutils_opencl.o)) $(foreach P,$(AVPROGS-yes),$(eval $(call DOFFTOOL,$(P)))) all: $(AVPROGS) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 3d428f3ee..6920ca076 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -38,6 +38,7 @@ #include "libswscale/swscale.h" #include "libswresample/swresample.h" #include "libpostproc/postprocess.h" +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" @@ -1702,7 +1703,7 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg) #endif while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) { - enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc); + enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc); printf("%c%c%c%c%c %-16s %d %2d\n", sws_isSupportedInput (pix_fmt) ? 'I' : '.', sws_isSupportedOutput(pix_fmt) ? 'O' : '.', diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 2997ee37b..87244891d 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -105,12 +105,6 @@ int opt_max_alloc(void *optctx, const char *opt, const char *arg); int opt_codec_debug(void *optctx, const char *opt, const char *arg); -#if CONFIG_OPENCL -int opt_opencl(void *optctx, const char *opt, const char *arg); - -int opt_opencl_bench(void *optctx, const char *opt, const char *arg); -#endif - /** * Limit the execution time. */ @@ -155,6 +149,7 @@ typedef struct SpecifierOpt { uint8_t *str; int i; int64_t i64; + uint64_t ui64; float f; double dbl; } u; @@ -206,17 +201,6 @@ typedef struct OptionDef { void show_help_options(const OptionDef *options, const char *msg, int req_flags, int rej_flags, int alt_flags); -#if CONFIG_OPENCL -#define CMDUTILS_COMMON_OPTIONS_OPENCL \ - { "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, \ - "run benchmark on all OpenCL devices and show results" }, \ - { "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, \ - "set OpenCL environment options" }, \ - -#else -#define CMDUTILS_COMMON_OPTIONS_OPENCL -#endif - #if CONFIG_AVDEVICE #define CMDUTILS_COMMON_OPTIONS_AVDEVICE \ { "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources }, \ @@ -256,7 +240,6 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags, { "max_alloc", HAS_ARG, { .func_arg = opt_max_alloc }, "set maximum size of a single allocated block", "bytes" }, \ { "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" }, \ { "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" }, \ - CMDUTILS_COMMON_OPTIONS_OPENCL \ CMDUTILS_COMMON_OPTIONS_AVDEVICE \ /** diff --git a/fftools/cmdutils_opencl.c b/fftools/cmdutils_opencl.c deleted file mode 100644 index 906aef483..000000000 --- a/fftools/cmdutils_opencl.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 "libavutil/time.h" -#include "libavutil/log.h" -#include "libavutil/opencl.h" -#include "libavutil/avstring.h" -#include "cmdutils.h" - -typedef struct { - int platform_idx; - int device_idx; - char device_name[64]; - int64_t runtime; -} OpenCLDeviceBenchmark; - -const char *ocl_bench_source = AV_OPENCL_KERNEL( -inline unsigned char clip_uint8(int a) -{ - if (a & (~0xFF)) - return (-a)>>31; - else - return a; -} - -kernel void unsharp_bench( - global unsigned char *src, - global unsigned char *dst, - global int *mask, - int width, - int height) -{ - int i, j, local_idx, lc_idx, sum = 0; - int2 thread_idx, block_idx, global_idx, lm_idx; - thread_idx.x = get_local_id(0); - thread_idx.y = get_local_id(1); - block_idx.x = get_group_id(0); - block_idx.y = get_group_id(1); - global_idx.x = get_global_id(0); - global_idx.y = get_global_id(1); - local uchar data[32][32]; - local int lc[128]; - - for (i = 0; i <= 1; i++) { - lm_idx.y = -8 + (block_idx.y + i) * 16 + thread_idx.y; - lm_idx.y = lm_idx.y < 0 ? 0 : lm_idx.y; - lm_idx.y = lm_idx.y >= height ? height - 1: lm_idx.y; - for (j = 0; j <= 1; j++) { - lm_idx.x = -8 + (block_idx.x + j) * 16 + thread_idx.x; - lm_idx.x = lm_idx.x < 0 ? 0 : lm_idx.x; - lm_idx.x = lm_idx.x >= width ? width - 1: lm_idx.x; - data[i*16 + thread_idx.y][j*16 + thread_idx.x] = src[lm_idx.y*width + lm_idx.x]; - } - } - local_idx = thread_idx.y*16 + thread_idx.x; - if (local_idx < 128) - lc[local_idx] = mask[local_idx]; - barrier(CLK_LOCAL_MEM_FENCE); - - \n#pragma unroll\n - for (i = -4; i <= 4; i++) { - lm_idx.y = 8 + i + thread_idx.y; - \n#pragma unroll\n - for (j = -4; j <= 4; j++) { - lm_idx.x = 8 + j + thread_idx.x; - lc_idx = (i + 4)*8 + j + 4; - sum += (int)data[lm_idx.y][lm_idx.x] * lc[lc_idx]; - } - } - int temp = (int)data[thread_idx.y + 8][thread_idx.x + 8]; - int res = temp + (((temp - (int)((sum + 1<<15) >> 16))) >> 16); - if (global_idx.x < width && global_idx.y < height) - dst[global_idx.x + global_idx.y*width] = clip_uint8(res); -} -); - -#define OCLCHECK(method, ... ) \ -do { \ - status = method(__VA_ARGS__); \ - if (status != CL_SUCCESS) { \ - av_log(NULL, AV_LOG_ERROR, # method " error '%s'\n", \ - av_opencl_errstr(status)); \ - ret = AVERROR_EXTERNAL; \ - goto end; \ - } \ -} while (0) - -#define CREATEBUF(out, flags, size) \ -do { \ - out = clCreateBuffer(ext_opencl_env->context, flags, size, NULL, &status); \ - if (status != CL_SUCCESS) { \ - av_log(NULL, AV_LOG_ERROR, "Could not create OpenCL buffer\n"); \ - ret = AVERROR_EXTERNAL; \ - goto end; \ - } \ -} while (0) - -static void fill_rand_int(int *data, int n) -{ - int i; - srand(av_gettime()); - for (i = 0; i < n; i++) - data[i] = rand(); -} - -#define OPENCL_NB_ITER 5 -static int64_t run_opencl_bench(AVOpenCLExternalEnv *ext_opencl_env) -{ - int i, arg = 0, width = 1920, height = 1088; - int64_t start, ret = 0; - cl_int status; - size_t kernel_len; - char *inbuf; - int *mask = NULL; - int buf_size = width * height * sizeof(char); - int mask_size = sizeof(uint32_t) * 128; - - cl_mem cl_mask = NULL, cl_inbuf = NULL, cl_outbuf = NULL; - cl_kernel kernel = NULL; - cl_program program = NULL; - size_t local_work_size_2d[2] = {16, 16}; - size_t global_work_size_2d[2] = {(size_t)width, (size_t)height}; - - if (!(inbuf = av_malloc(buf_size)) || !(mask = av_malloc(mask_size))) { - av_log(NULL, AV_LOG_ERROR, "Out of memory\n"); - ret = AVERROR(ENOMEM); - goto end; - } - fill_rand_int((int*)inbuf, buf_size/4); - fill_rand_int(mask, mask_size/4); - - CREATEBUF(cl_mask, CL_MEM_READ_ONLY, mask_size); - CREATEBUF(cl_inbuf, CL_MEM_READ_ONLY, buf_size); - CREATEBUF(cl_outbuf, CL_MEM_READ_WRITE, buf_size); - - kernel_len = strlen(ocl_bench_source); - program = clCreateProgramWithSource(ext_opencl_env->context, 1, &ocl_bench_source, - &kernel_len, &status); - if (status != CL_SUCCESS || !program) { - av_log(NULL, AV_LOG_ERROR, "OpenCL unable to create benchmark program\n"); - ret = AVERROR_EXTERNAL; - goto end; - } - status = clBuildProgram(program, 1, &(ext_opencl_env->device_id), NULL, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(NULL, AV_LOG_ERROR, "OpenCL unable to build benchmark program\n"); - ret = AVERROR_EXTERNAL; - goto end; - } - kernel = clCreateKernel(program, "unsharp_bench", &status); - if (status != CL_SUCCESS) { - av_log(NULL, AV_LOG_ERROR, "OpenCL unable to create benchmark kernel\n"); - ret = AVERROR_EXTERNAL; - goto end; - } - - OCLCHECK(clEnqueueWriteBuffer, ext_opencl_env->command_queue, cl_inbuf, CL_TRUE, 0, - buf_size, inbuf, 0, NULL, NULL); - OCLCHECK(clEnqueueWriteBuffer, ext_opencl_env->command_queue, cl_mask, CL_TRUE, 0, - mask_size, mask, 0, NULL, NULL); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_inbuf); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_outbuf); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_mask); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &width); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &height); - - start = av_gettime_relative(); - for (i = 0; i < OPENCL_NB_ITER; i++) - OCLCHECK(clEnqueueNDRangeKernel, ext_opencl_env->command_queue, kernel, 2, NULL, - global_work_size_2d, local_work_size_2d, 0, NULL, NULL); - clFinish(ext_opencl_env->command_queue); - ret = (av_gettime_relative() - start)/OPENCL_NB_ITER; -end: - if (kernel) - clReleaseKernel(kernel); - if (program) - clReleaseProgram(program); - if (cl_inbuf) - clReleaseMemObject(cl_inbuf); - if (cl_outbuf) - clReleaseMemObject(cl_outbuf); - if (cl_mask) - clReleaseMemObject(cl_mask); - av_free(inbuf); - av_free(mask); - return ret; -} - -static int compare_ocl_device_desc(const void *a, const void *b) -{ - const OpenCLDeviceBenchmark* va = (const OpenCLDeviceBenchmark*)a; - const OpenCLDeviceBenchmark* vb = (const OpenCLDeviceBenchmark*)b; - return FFDIFFSIGN(va->runtime , vb->runtime); -} - -int opt_opencl_bench(void *optctx, const char *opt, const char *arg) -{ - int i, j, nb_devices = 0, count = 0, ret = 0; - int64_t score = 0; - AVOpenCLDeviceList *device_list; - AVOpenCLDeviceNode *device_node = NULL; - OpenCLDeviceBenchmark *devices = NULL; - cl_platform_id platform; - - ret = av_opencl_get_device_list(&device_list); - if (ret < 0) { - return ret; - } - for (i = 0; i < device_list->platform_num; i++) - nb_devices += device_list->platform_node[i]->device_num; - if (!nb_devices) { - av_log(NULL, AV_LOG_ERROR, "No OpenCL device detected!\n"); - av_opencl_free_device_list(&device_list); - return AVERROR(EINVAL); - } - if (!(devices = av_malloc_array(nb_devices, sizeof(OpenCLDeviceBenchmark)))) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate buffer\n"); - av_opencl_free_device_list(&device_list); - return AVERROR(ENOMEM); - } - - for (i = 0; i < device_list->platform_num; i++) { - for (j = 0; j < device_list->platform_node[i]->device_num; j++) { - device_node = device_list->platform_node[i]->device_node[j]; - platform = device_list->platform_node[i]->platform_id; - score = av_opencl_benchmark(device_node, platform, run_opencl_bench); - if (score > 0) { - devices[count].platform_idx = i; - devices[count].device_idx = j; - devices[count].runtime = score; - av_strlcpy(devices[count].device_name, device_node->device_name, - sizeof(devices[count].device_name)); - count++; - } - } - } - qsort(devices, count, sizeof(OpenCLDeviceBenchmark), compare_ocl_device_desc); - fprintf(stderr, "platform_idx\tdevice_idx\tdevice_name\truntime\n"); - for (i = 0; i < count; i++) - fprintf(stdout, "%d\t%d\t%s\t%"PRId64"\n", - devices[i].platform_idx, devices[i].device_idx, - devices[i].device_name, devices[i].runtime); - - av_opencl_free_device_list(&device_list); - av_free(devices); - return 0; -} - -int opt_opencl(void *optctx, const char *opt, const char *arg) -{ - char *key, *value; - const char *opts = arg; - int ret = 0; - while (*opts) { - ret = av_opt_get_key_value(&opts, "=", ":", 0, &key, &value); - if (ret < 0) - return ret; - ret = av_opencl_set_option(key, value); - if (ret < 0) - return ret; - if (*opts) - opts++; - } - return ret; -} diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 3ee31473d..528849a2c 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -61,6 +61,7 @@ #include "libavutil/timestamp.h" #include "libavutil/bprint.h" #include "libavutil/time.h" +#include "libavutil/thread.h" #include "libavutil/threadmessage.h" #include "libavcodec/mathops.h" #include "libavformat/os_support.h" @@ -98,10 +99,6 @@ #include #endif -#if HAVE_PTHREADS -#include -#endif - #include #include "ffmpeg.h" @@ -161,7 +158,7 @@ static struct termios oldtty; static int restore_tty; #endif -#if HAVE_PTHREADS +#if HAVE_THREADS static void free_input_threads(void); #endif @@ -220,13 +217,18 @@ static void sub2video_push_ref(InputStream *ist, int64_t pts) { AVFrame *frame = ist->sub2video.frame; int i; + int ret; av_assert1(frame->data[0]); ist->sub2video.last_pts = frame->pts = pts; - for (i = 0; i < ist->nb_filters; i++) - av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame, - AV_BUFFERSRC_FLAG_KEEP_REF | - AV_BUFFERSRC_FLAG_PUSH); + for (i = 0; i < ist->nb_filters; i++) { + ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame, + AV_BUFFERSRC_FLAG_KEEP_REF | + AV_BUFFERSRC_FLAG_PUSH); + if (ret != AVERROR_EOF && ret < 0) + av_log(NULL, AV_LOG_WARNING, "Error while add the frame to buffer source(%s).\n", + av_err2str(ret)); + } } void sub2video_update(InputStream *ist, AVSubtitle *sub) @@ -295,11 +297,15 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts) static void sub2video_flush(InputStream *ist) { int i; + int ret; if (ist->sub2video.end_pts < INT64_MAX) sub2video_update(ist, NULL); - for (i = 0; i < ist->nb_filters; i++) - av_buffersrc_add_frame(ist->filters[i]->filter, NULL); + for (i = 0; i < ist->nb_filters; i++) { + ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL); + if (ret != AVERROR_EOF && ret < 0) + av_log(NULL, AV_LOG_WARNING, "Flush the frame error.\n"); + } } /* end of sub2video hack */ @@ -327,13 +333,14 @@ static int main_return_code = 0; static void sigterm_handler(int sig) { + int ret; received_sigterm = sig; received_nb_signals++; term_exit_sigsafe(); if(received_nb_signals > 3) { - write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n", - strlen("Received > 3 system signals, hard exiting\n")); - + ret = write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n", + strlen("Received > 3 system signals, hard exiting\n")); + if (ret < 0) { /* Do nothing */ }; exit(123); } } @@ -568,7 +575,7 @@ static void ffmpeg_cleanup(int ret) av_freep(&output_streams[i]); } -#if HAVE_PTHREADS +#if HAVE_THREADS free_input_threads(); #endif for (i = 0; i < nb_input_files; i++) { @@ -1199,24 +1206,6 @@ static void do_video_out(OutputFile *of, #endif return; -#if FF_API_LAVF_FMT_RAWPICTURE - if (of->ctx->oformat->flags & AVFMT_RAWPICTURE && - enc->codec->id == AV_CODEC_ID_RAWVIDEO) { - /* raw pictures are written as AVPicture structure to - avoid any copies. We support temporarily the older - method. */ - if (in_picture->interlaced_frame) - mux_par->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT; - else - mux_par->field_order = AV_FIELD_PROGRESSIVE; - pkt.data = (uint8_t *)in_picture; - pkt.size = sizeof(AVPicture); - pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->mux_timebase); - pkt.flags |= AV_PKT_FLAG_KEY; - - output_packet(of, &pkt, ost, 0); - } else -#endif { int forced_keyframe = 0; double pts_time; @@ -1897,10 +1886,6 @@ static void flush_encoders(void) if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1) continue; -#if FF_API_LAVF_FMT_RAWPICTURE - if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (of->ctx->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO) - continue; -#endif if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO) continue; @@ -1991,11 +1976,16 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p InputFile *f = input_files [ist->file_index]; int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time; int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->mux_timebase); - AVPicture pict; - AVPacket opkt; + AVPacket opkt = { 0 }; av_init_packet(&opkt); + // EOF: flush output bitstream filters. + if (!pkt) { + output_packet(of, &opkt, ost, 1); + return; + } + if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && !ost->copy_initial_nonkeyframes) return; @@ -2079,23 +2069,6 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p } av_copy_packet_side_data(&opkt, pkt); -#if FF_API_LAVF_FMT_RAWPICTURE - if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - ost->st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO && - (of->ctx->oformat->flags & AVFMT_RAWPICTURE)) { - /* store AVPicture in AVPacket, as expected by the output format */ - int ret = avpicture_fill(&pict, opkt.data, ost->st->codecpar->format, ost->st->codecpar->width, ost->st->codecpar->height); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "avpicture_fill failed: %s\n", - av_err2str(ret)); - exit_program(1); - } - opkt.data = (uint8_t *)&pict; - opkt.size = sizeof(AVPicture); - opkt.flags |= AV_PKT_FLAG_KEY; - } -#endif - output_packet(of, &opkt, ost, 0); } @@ -2733,7 +2706,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo } /* handle stream copy */ - if (!ist->decoding_needed) { + if (!ist->decoding_needed && pkt) { ist->dts = ist->next_dts; switch (ist->dec_ctx->codec_type) { case AVMEDIA_TYPE_AUDIO: @@ -2759,7 +2732,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo ist->pts = ist->dts; ist->next_pts = ist->next_dts; } - for (i = 0; pkt && i < nb_output_streams; i++) { + for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; if (!check_output_constraints(ist, ost) || ost->encoding_needed) @@ -2816,44 +2789,77 @@ fail: av_freep(&avc); } -static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt) -{ - int i; - for (i = 0; hwaccels[i].name; i++) - if (hwaccels[i].pix_fmt == pix_fmt) - return &hwaccels[i]; - return NULL; -} - static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts) { InputStream *ist = s->opaque; const enum AVPixelFormat *p; int ret; - for (p = pix_fmts; *p != -1; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p); - const HWAccel *hwaccel; + const AVCodecHWConfig *config = NULL; + int i; if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) break; - hwaccel = get_hwaccel(*p); - if (!hwaccel || - (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) || - (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != hwaccel->id)) - continue; + if (ist->hwaccel_id == HWACCEL_GENERIC || + ist->hwaccel_id == HWACCEL_AUTO) { + for (i = 0;; i++) { + config = avcodec_get_hw_config(s->codec, i); + if (!config) + break; + if (!(config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) + continue; + if (config->pix_fmt == *p) + break; + } + } + if (config) { + if (config->device_type != ist->hwaccel_device_type) { + // Different hwaccel offered, ignore. + continue; + } - ret = hwaccel->init(s); - if (ret < 0) { - if (ist->hwaccel_id == hwaccel->id) { + ret = hwaccel_decode_init(s); + if (ret < 0) { + if (ist->hwaccel_id == HWACCEL_GENERIC) { + av_log(NULL, AV_LOG_FATAL, + "%s hwaccel requested for input stream #%d:%d, " + "but cannot be initialized.\n", + av_hwdevice_get_type_name(config->device_type), + ist->file_index, ist->st->index); + return AV_PIX_FMT_NONE; + } + continue; + } + } else { + const HWAccel *hwaccel = NULL; + int i; + for (i = 0; hwaccels[i].name; i++) { + if (hwaccels[i].pix_fmt == *p) { + hwaccel = &hwaccels[i]; + break; + } + } + if (!hwaccel) { + // No hwaccel supporting this pixfmt. + continue; + } + if (hwaccel->id != ist->hwaccel_id) { + // Does not match requested hwaccel. + continue; + } + + ret = hwaccel->init(s); + if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "%s hwaccel requested for input stream #%d:%d, " "but cannot be initialized.\n", hwaccel->name, ist->file_index, ist->st->index); return AV_PIX_FMT_NONE; } - continue; } if (ist->hw_frames_ctx) { @@ -2862,8 +2868,7 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat return AV_PIX_FMT_NONE; } - ist->active_hwaccel_id = hwaccel->id; - ist->hwaccel_pix_fmt = *p; + ist->hwaccel_pix_fmt = *p; break; } @@ -2910,7 +2915,7 @@ static int init_input_stream(int ist_index, char *error, int error_len) /* Useful for subtitles retiming by lavf (FIXME), skipping samples in * audio, and video decoders such as cuvid or mediacodec */ - av_codec_set_pkt_timebase(ist->dec_ctx, ist->st->time_base); + ist->dec_ctx->pkt_timebase = ist->st->time_base; if (!av_dict_get(ist->decoder_opts, "threads", NULL, 0)) av_dict_set(&ist->decoder_opts, "threads", "auto", 0); @@ -3160,7 +3165,7 @@ static void set_encoder_id(OutputFile *of, OutputStream *ost) uint8_t *encoder_string; int encoder_string_len; int format_flags = 0; - int codec_flags = 0; + int codec_flags = ost->enc_ctx->flags; if (av_dict_get(ost->st->metadata, "encoder", NULL, 0)) return; @@ -3988,7 +3993,7 @@ static int check_keyboard_interaction(int64_t cur_time) return 0; } -#if HAVE_PTHREADS +#if HAVE_THREADS static void *input_thread(void *arg) { InputFile *f = arg; @@ -4098,7 +4103,7 @@ static int get_input_packet(InputFile *f, AVPacket *pkt) } } -#if HAVE_PTHREADS +#if HAVE_THREADS if (nb_input_files > 1) return get_input_packet_mt(f, pkt); #endif @@ -4180,14 +4185,17 @@ static int seek_to_start(InputFile *ifile, AVFormatContext *is) AVRational sample_rate = {1, avctx->sample_rate}; duration = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base); - } else + } else { continue; + } } else { if (ist->framerate.num) { - duration = av_rescale_q(1, ist->framerate, ist->st->time_base); + duration = av_rescale_q(1, av_inv_q(ist->framerate), ist->st->time_base); } else if (ist->st->avg_frame_rate.num) { - duration = av_rescale_q(1, ist->st->avg_frame_rate, ist->st->time_base); - } else duration = 1; + duration = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate), ist->st->time_base); + } else { + duration = 1; + } } if (!ifile->duration) ifile->time_base = ist->st->time_base; @@ -4229,9 +4237,11 @@ static int process_input(int file_index) return ret; } if (ret < 0 && ifile->loop) { - if ((ret = seek_to_start(ifile, is)) < 0) - return ret; - ret = get_input_packet(ifile, &pkt); + ret = seek_to_start(ifile, is); + if (ret < 0) + av_log(NULL, AV_LOG_WARNING, "Seek to start failed.\n"); + else + ret = get_input_packet(ifile, &pkt); if (ret == AVERROR(EAGAIN)) { ifile->eagain = 1; return ret; @@ -4536,6 +4546,15 @@ static int transcode_step(void) } if (ost->filter && ost->filter->graph->graph) { + if (!ost->initialized) { + char error[1024] = {0}; + ret = init_output_stream(ost, error, sizeof(error)); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error initializing output stream %d:%d -- %s\n", + ost->file_index, ost->index, error); + exit_program(1); + } + } if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0) return ret; if (!ist) @@ -4593,7 +4612,7 @@ static int transcode(void) timer_start = av_gettime_relative(); -#if HAVE_PTHREADS +#if HAVE_THREADS if ((ret = init_input_threads()) < 0) goto fail; #endif @@ -4624,14 +4643,14 @@ static int transcode(void) /* dump report by using the output first video and audio streams */ print_report(0, timer_start, cur_time); } -#if HAVE_PTHREADS +#if HAVE_THREADS free_input_threads(); #endif /* at the end of stream, we must flush the decoder buffers */ for (i = 0; i < nb_input_streams; i++) { ist = input_streams[i]; - if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) { + if (!input_files[ist->file_index]->eof_reached) { process_input_packet(ist, NULL, 0); } } @@ -4690,7 +4709,7 @@ static int transcode(void) ret = 0; fail: -#if HAVE_PTHREADS +#if HAVE_THREADS free_input_threads(); #endif diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index f6c76bcc5..8195f73e8 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -25,10 +25,6 @@ #include #include -#if HAVE_PTHREADS -#include -#endif - #include "cmdutils.h" #include "libavformat/avformat.h" @@ -45,6 +41,7 @@ #include "libavutil/hwcontext.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" +#include "libavutil/thread.h" #include "libavutil/threadmessage.h" #include "libswresample/swresample.h" @@ -61,14 +58,10 @@ enum HWAccelID { HWACCEL_NONE = 0, HWACCEL_AUTO, - HWACCEL_VDPAU, - HWACCEL_DXVA2, - HWACCEL_VDA, + HWACCEL_GENERIC, HWACCEL_VIDEOTOOLBOX, HWACCEL_QSV, - HWACCEL_VAAPI, HWACCEL_CUVID, - HWACCEL_D3D11VA, }; typedef struct HWAccel { @@ -76,7 +69,6 @@ typedef struct HWAccel { int (*init)(AVCodecContext *s); enum HWAccelID id; enum AVPixelFormat pix_fmt; - enum AVHWDeviceType device_type; } HWAccel; typedef struct HWDevice { @@ -161,6 +153,7 @@ typedef struct OptionsContext { float mux_preload; float mux_max_delay; int shortest; + int bitexact; int video_disable; int audio_disable; @@ -369,11 +362,11 @@ typedef struct InputStream { /* hwaccel options */ enum HWAccelID hwaccel_id; + enum AVHWDeviceType hwaccel_device_type; char *hwaccel_device; enum AVPixelFormat hwaccel_output_format; /* hwaccel context */ - enum HWAccelID active_hwaccel_id; void *hwaccel_ctx; void (*hwaccel_uninit)(AVCodecContext *s); int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags); @@ -419,7 +412,7 @@ typedef struct InputFile { int rate_emu; int accurate_seek; -#if HAVE_PTHREADS +#if HAVE_THREADS AVThreadMessageQueue *in_thread_queue; pthread_t thread; /* thread reading from this file */ int non_blocking; /* reading packets from the thread should not block */ @@ -624,7 +617,6 @@ extern const AVIOInterruptCB int_cb; extern const OptionDef options[]; extern const HWAccel hwaccels[]; -extern int hwaccel_lax_profile_check; extern AVBufferRef *hw_device_ctx; #if CONFIG_QSV extern char *qsv_device; @@ -662,7 +654,6 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame); int ffmpeg_parse_options(int argc, char **argv); -int vda_init(AVCodecContext *s); int videotoolbox_init(AVCodecContext *s); int qsv_init(AVCodecContext *s); int cuvid_init(AVCodecContext *s); diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index aacc18505..877fd670e 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -340,6 +340,7 @@ int init_complex_filtergraph(FilterGraph *fg) graph = avfilter_graph_alloc(); if (!graph) return AVERROR(ENOMEM); + graph->nb_threads = 1; ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs); if (ret < 0) diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c index a4d1cada5..2ec181385 100644 --- a/fftools/ffmpeg_hw.c +++ b/fftools/ffmpeg_hw.c @@ -64,6 +64,31 @@ static HWDevice *hw_device_add(void) return hw_devices[nb_hw_devices++]; } +static char *hw_device_default_name(enum AVHWDeviceType type) +{ + // Make an automatic name of the form "type%d". We arbitrarily + // limit at 1000 anonymous devices of the same type - there is + // probably something else very wrong if you get to this limit. + const char *type_name = av_hwdevice_get_type_name(type); + char *name; + size_t index_pos; + int index, index_limit = 1000; + index_pos = strlen(type_name); + name = av_malloc(index_pos + 4); + if (!name) + return NULL; + for (index = 0; index < index_limit; index++) { + snprintf(name, index_pos + 4, "%s%d", type_name, index); + if (!hw_device_get_by_name(name)) + break; + } + if (index >= index_limit) { + av_freep(&name); + return NULL; + } + return name; +} + int hw_device_init_from_string(const char *arg, HWDevice **dev_out) { // "type=name:device,key=value,key2=value2" @@ -111,27 +136,11 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) p += 1 + k; } else { - // Give the device an automatic name of the form "type%d". - // We arbitrarily limit at 1000 anonymous devices of the same - // type - there is probably something else very wrong if you - // get to this limit. - size_t index_pos; - int index, index_limit = 1000; - index_pos = strlen(type_name); - name = av_malloc(index_pos + 4); + name = hw_device_default_name(type); if (!name) { err = AVERROR(ENOMEM); goto fail; } - for (index = 0; index < index_limit; index++) { - snprintf(name, index_pos + 4, "%s%d", type_name, index); - if (!hw_device_get_by_name(name)) - break; - } - if (index >= index_limit) { - errmsg = "too many devices"; - goto invalid; - } } if (!*p) { @@ -214,6 +223,49 @@ fail: goto done; } +static int hw_device_init_from_type(enum AVHWDeviceType type, + const char *device, + HWDevice **dev_out) +{ + AVBufferRef *device_ref = NULL; + HWDevice *dev; + char *name; + int err; + + name = hw_device_default_name(type); + if (!name) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0); + if (err < 0) { + av_log(NULL, AV_LOG_ERROR, + "Device creation failed: %d.\n", err); + goto fail; + } + + dev = hw_device_add(); + if (!dev) { + err = AVERROR(ENOMEM); + goto fail; + } + + dev->name = name; + dev->type = type; + dev->device_ref = device_ref; + + if (dev_out) + *dev_out = dev; + + return 0; + +fail: + av_freep(&name); + av_buffer_unref(&device_ref); + return err; +} + void hw_device_free_all(void) { int i; @@ -226,80 +278,130 @@ void hw_device_free_all(void) nb_hw_devices = 0; } -static enum AVHWDeviceType hw_device_match_type_by_hwaccel(enum HWAccelID hwaccel_id) +static HWDevice *hw_device_match_by_codec(const AVCodec *codec) { + const AVCodecHWConfig *config; + HWDevice *dev; int i; - if (hwaccel_id == HWACCEL_NONE) - return AV_HWDEVICE_TYPE_NONE; - for (i = 0; hwaccels[i].name; i++) { - if (hwaccels[i].id == hwaccel_id) - return hwaccels[i].device_type; + for (i = 0;; i++) { + config = avcodec_get_hw_config(codec, i); + if (!config) + return NULL; + if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) + continue; + dev = hw_device_get_by_type(config->device_type); + if (dev) + return dev; } - return AV_HWDEVICE_TYPE_NONE; -} - -static enum AVHWDeviceType hw_device_match_type_in_name(const char *codec_name) -{ - const char *type_name; - enum AVHWDeviceType type; - for (type = av_hwdevice_iterate_types(AV_HWDEVICE_TYPE_NONE); - type != AV_HWDEVICE_TYPE_NONE; - type = av_hwdevice_iterate_types(type)) { - type_name = av_hwdevice_get_type_name(type); - if (strstr(codec_name, type_name)) - return type; - } - return AV_HWDEVICE_TYPE_NONE; } int hw_device_setup_for_decode(InputStream *ist) { + const AVCodecHWConfig *config; enum AVHWDeviceType type; - HWDevice *dev; - int err; + HWDevice *dev = NULL; + int err, auto_device = 0; if (ist->hwaccel_device) { dev = hw_device_get_by_name(ist->hwaccel_device); if (!dev) { - char *tmp; - type = hw_device_match_type_by_hwaccel(ist->hwaccel_id); - if (type == AV_HWDEVICE_TYPE_NONE) { - // No match - this isn't necessarily invalid, though, - // because an explicit device might not be needed or - // the hwaccel setup could be handled elsewhere. + if (ist->hwaccel_id == HWACCEL_AUTO) { + auto_device = 1; + } else if (ist->hwaccel_id == HWACCEL_GENERIC) { + type = ist->hwaccel_device_type; + err = hw_device_init_from_type(type, ist->hwaccel_device, + &dev); + } else { + // This will be dealt with by API-specific initialisation + // (using hwaccel_device), so nothing further needed here. return 0; } - tmp = av_asprintf("%s:%s", av_hwdevice_get_type_name(type), - ist->hwaccel_device); - if (!tmp) - return AVERROR(ENOMEM); - err = hw_device_init_from_string(tmp, &dev); - av_free(tmp); - if (err < 0) - return err; + } else { + if (ist->hwaccel_id == HWACCEL_AUTO) { + ist->hwaccel_device_type = dev->type; + } else if (ist->hwaccel_device_type != dev->type) { + av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device " + "specified for decoder: device %s of type %s is not " + "usable with hwaccel %s.\n", dev->name, + av_hwdevice_get_type_name(dev->type), + av_hwdevice_get_type_name(ist->hwaccel_device_type)); + return AVERROR(EINVAL); + } } } else { - if (ist->hwaccel_id != HWACCEL_NONE) - type = hw_device_match_type_by_hwaccel(ist->hwaccel_id); - else - type = hw_device_match_type_in_name(ist->dec->name); - if (type != AV_HWDEVICE_TYPE_NONE) { + if (ist->hwaccel_id == HWACCEL_AUTO) { + auto_device = 1; + } else if (ist->hwaccel_id == HWACCEL_GENERIC) { + type = ist->hwaccel_device_type; dev = hw_device_get_by_type(type); - if (!dev) { - hw_device_init_from_string(av_hwdevice_get_type_name(type), - &dev); - } + if (!dev) + err = hw_device_init_from_type(type, NULL, &dev); } else { - // No device required. + dev = hw_device_match_by_codec(ist->dec); + if (!dev) { + // No device for this codec, but not using generic hwaccel + // and therefore may well not need one - ignore. + return 0; + } + } + } + + if (auto_device) { + int i; + if (!avcodec_get_hw_config(ist->dec, 0)) { + // Decoder does not support any hardware devices. + return 0; + } + for (i = 0; !dev; i++) { + config = avcodec_get_hw_config(ist->dec, i); + if (!config) + break; + type = config->device_type; + dev = hw_device_get_by_type(type); + if (dev) { + av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " + "hwaccel type %s with existing device %s.\n", + av_hwdevice_get_type_name(type), dev->name); + } + } + for (i = 0; !dev; i++) { + config = avcodec_get_hw_config(ist->dec, i); + if (!config) + break; + type = config->device_type; + // Try to make a new device of this type. + err = hw_device_init_from_type(type, ist->hwaccel_device, + &dev); + if (err < 0) { + // Can't make a device of this type. + continue; + } + if (ist->hwaccel_device) { + av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " + "hwaccel type %s with new device created " + "from %s.\n", av_hwdevice_get_type_name(type), + ist->hwaccel_device); + } else { + av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " + "hwaccel type %s with new default device.\n", + av_hwdevice_get_type_name(type)); + } + } + if (dev) { + ist->hwaccel_device_type = type; + } else { + av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel " + "disabled: no device found.\n"); + ist->hwaccel_id = HWACCEL_NONE; return 0; } } if (!dev) { - av_log(ist->dec_ctx, AV_LOG_WARNING, "No device available " - "for decoder (device type %s for codec %s).\n", + av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available " + "for decoder: device type %s needed for codec %s.\n", av_hwdevice_get_type_name(type), ist->dec->name); - return 0; + return err; } ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); @@ -311,24 +413,16 @@ int hw_device_setup_for_decode(InputStream *ist) int hw_device_setup_for_encode(OutputStream *ost) { - enum AVHWDeviceType type; HWDevice *dev; - type = hw_device_match_type_in_name(ost->enc->name); - if (type != AV_HWDEVICE_TYPE_NONE) { - dev = hw_device_get_by_type(type); - if (!dev) { - av_log(ost->enc_ctx, AV_LOG_WARNING, "No device available " - "for encoder (device type %s for codec %s).\n", - av_hwdevice_get_type_name(type), ost->enc->name); - return 0; - } + dev = hw_device_match_by_codec(ost->enc); + if (dev) { ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); if (!ost->enc_ctx->hw_device_ctx) return AVERROR(ENOMEM); return 0; } else { - // No device required. + // No device required, or no device available. return 0; } } diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 100fa76e4..92199b3ac 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -66,41 +66,17 @@ } const HWAccel hwaccels[] = { -#if HAVE_VDPAU_X11 - { "vdpau", hwaccel_decode_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU, - AV_HWDEVICE_TYPE_VDPAU }, -#endif -#if CONFIG_D3D11VA - { "d3d11va", hwaccel_decode_init, HWACCEL_D3D11VA, AV_PIX_FMT_D3D11, - AV_HWDEVICE_TYPE_D3D11VA }, -#endif -#if CONFIG_DXVA2 - { "dxva2", hwaccel_decode_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD, - AV_HWDEVICE_TYPE_DXVA2 }, -#endif -#if CONFIG_VDA - { "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA, - AV_HWDEVICE_TYPE_NONE }, -#endif #if CONFIG_VIDEOTOOLBOX - { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX, - AV_HWDEVICE_TYPE_NONE }, + { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX }, #endif #if CONFIG_LIBMFX - { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV, - AV_HWDEVICE_TYPE_NONE }, -#endif -#if CONFIG_VAAPI - { "vaapi", hwaccel_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI, - AV_HWDEVICE_TYPE_VAAPI }, + { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV }, #endif #if CONFIG_CUVID - { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA, - AV_HWDEVICE_TYPE_NONE }, + { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA }, #endif { 0 }, }; -int hwaccel_lax_profile_check = 0; AVBufferRef *hw_device_ctx; HWDevice *filter_hw_device; @@ -141,7 +117,6 @@ static int file_overwrite = 0; static int no_file_overwrite = 0; static int do_psnr = 0; static int input_sync; -static int override_ffserver = 0; static int input_stream_potentially_available = 0; static int ignore_unknown_streams = 0; static int copy_unknown_streams = 0; @@ -195,12 +170,15 @@ static void init_options(OptionsContext *o) static int show_hwaccels(void *optctx, const char *opt, const char *arg) { + enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; int i; printf("Hardware acceleration methods:\n"); - for (i = 0; hwaccels[i].name; i++) { + while ((type = av_hwdevice_iterate_types(type)) != + AV_HWDEVICE_TYPE_NONE) + printf("%s\n", av_hwdevice_get_type_name(type)); + for (i = 0; hwaccels[i].name; i++) printf("%s\n", hwaccels[i].name); - } printf("\n"); return 0; } @@ -723,7 +701,8 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) AVStream *st = ic->streams[i]; AVCodecParameters *par = st->codecpar; InputStream *ist = av_mallocz(sizeof(*ist)); - char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL; + char *framerate = NULL, *hwaccel_device = NULL; + const char *hwaccel = NULL; char *hwaccel_output_format = NULL; char *codec_tag = NULL; char *next; @@ -787,20 +766,20 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) exit_program(1); } + if (o->bitexact) + ist->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT; + switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: if(!ist->dec) ist->dec = avcodec_find_decoder(par->codec_id); #if FF_API_LOWRES - if (av_codec_get_lowres(st->codec)) { - av_codec_set_lowres(ist->dec_ctx, av_codec_get_lowres(st->codec)); + if (st->codec->lowres) { + ist->dec_ctx->lowres = st->codec->lowres; ist->dec_ctx->width = st->codec->width; ist->dec_ctx->height = st->codec->height; ist->dec_ctx->coded_width = st->codec->coded_width; ist->dec_ctx->coded_height = st->codec->coded_height; -#if FF_API_EMU_EDGE - ist->dec_ctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif } #endif @@ -820,11 +799,16 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st); if (hwaccel) { + // The NVDEC hwaccels use a CUDA device, so remap the name here. + if (!strcmp(hwaccel, "nvdec")) + hwaccel = "cuda"; + if (!strcmp(hwaccel, "none")) ist->hwaccel_id = HWACCEL_NONE; else if (!strcmp(hwaccel, "auto")) ist->hwaccel_id = HWACCEL_AUTO; else { + enum AVHWDeviceType type; int i; for (i = 0; hwaccels[i].name; i++) { if (!strcmp(hwaccels[i].name, hwaccel)) { @@ -833,10 +817,23 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) } } + if (!ist->hwaccel_id) { + type = av_hwdevice_find_type_by_name(hwaccel); + if (type != AV_HWDEVICE_TYPE_NONE) { + ist->hwaccel_id = HWACCEL_GENERIC; + ist->hwaccel_device_type = type; + } + } + if (!ist->hwaccel_id) { av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n", hwaccel); av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: "); + type = AV_HWDEVICE_TYPE_NONE; + while ((type = av_hwdevice_iterate_types(type)) != + AV_HWDEVICE_TYPE_NONE) + av_log(NULL, AV_LOG_FATAL, "%s ", + av_hwdevice_get_type_name(type)); for (i = 0; hwaccels[i].name; i++) av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name); av_log(NULL, AV_LOG_FATAL, "\n"); @@ -977,6 +974,21 @@ static int open_input_file(OptionsContext *o, const char *filename) char * data_codec_name = NULL; int scan_all_pmts_set = 0; + if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) { + o->stop_time = INT64_MAX; + av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n"); + } + + if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) { + int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time; + if (o->stop_time <= start_time) { + av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n"); + exit_program(1); + } else { + o->recording_time = o->stop_time - start_time; + } + } + if (o->format) { if (!(file_iformat = av_find_input_format(o->format))) { av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format); @@ -996,7 +1008,6 @@ static int open_input_file(OptionsContext *o, const char *filename) print_error(filename, AVERROR(ENOMEM)); exit_program(1); } - ic->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; if (o->nb_audio_sample_rate) { av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0); } @@ -1031,25 +1042,23 @@ static int open_input_file(OptionsContext *o, const char *filename) MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s"); MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d"); - ic->video_codec_id = video_codec_name ? - find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE; - ic->audio_codec_id = audio_codec_name ? - find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE; - ic->subtitle_codec_id= subtitle_codec_name ? - find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE; - ic->data_codec_id = data_codec_name ? - find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE; - if (video_codec_name) - av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)); + ic->video_codec = find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0); if (audio_codec_name) - av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)); + ic->audio_codec = find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0); if (subtitle_codec_name) - av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)); + ic->subtitle_codec = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0); if (data_codec_name) - av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)); + ic->data_codec = find_codec_or_die(data_codec_name , AVMEDIA_TYPE_DATA , 0); + + ic->video_codec_id = video_codec_name ? ic->video_codec->id : AV_CODEC_ID_NONE; + ic->audio_codec_id = audio_codec_name ? ic->audio_codec->id : AV_CODEC_ID_NONE; + ic->subtitle_codec_id = subtitle_codec_name ? ic->subtitle_codec->id : AV_CODEC_ID_NONE; + ic->data_codec_id = data_codec_name ? ic->data_codec->id : AV_CODEC_ID_NONE; ic->flags |= AVFMT_FLAG_NONBLOCK; + if (o->bitexact) + ic->flags |= AVFMT_FLAG_BITEXACT; ic->interrupt_callback = int_cb; if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { @@ -1151,7 +1160,7 @@ static int open_input_file(OptionsContext *o, const char *filename) f->loop = o->loop; f->duration = 0; f->time_base = (AVRational){ 1, 1 }; -#if HAVE_PTHREADS +#if HAVE_THREADS f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8; #endif @@ -1371,6 +1380,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL); } + + if (o->bitexact) + ost->enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT; + MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st); if (time_base) { AVRational q; @@ -1663,7 +1676,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n"); exit_program(1); } - av_codec_set_chroma_intra_matrix(video_enc, p); + video_enc->chroma_intra_matrix = p; parse_matrix_coeffs(p, chroma_intra_matrix); } MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st); @@ -1983,57 +1996,6 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) return 0; } -static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) -{ - int i, err; - AVFormatContext *ic = avformat_alloc_context(); - - ic->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - ic->interrupt_callback = int_cb; - err = avformat_open_input(&ic, filename, NULL, NULL); - if (err < 0) - return err; - /* copy stream format */ - for(i=0;inb_streams;i++) { - AVStream *st; - OutputStream *ost; - AVCodec *codec; - const char *enc_config; - - codec = avcodec_find_encoder(ic->streams[i]->codecpar->codec_id); - if (!codec) { - av_log(s, AV_LOG_ERROR, "no encoder found for codec id %i\n", ic->streams[i]->codecpar->codec_id); - return AVERROR(EINVAL); - } - if (codec->type == AVMEDIA_TYPE_AUDIO) - opt_audio_codec(o, "c:a", codec->name); - else if (codec->type == AVMEDIA_TYPE_VIDEO) - opt_video_codec(o, "c:v", codec->name); - ost = new_output_stream(o, s, codec->type, -1); - st = ost->st; - - avcodec_get_context_defaults3(st->codec, codec); - enc_config = av_stream_get_recommended_encoder_configuration(ic->streams[i]); - if (enc_config) { - AVDictionary *opts = NULL; - av_dict_parse_string(&opts, enc_config, "=", ",", 0); - av_opt_set_dict2(st->codec, &opts, AV_OPT_SEARCH_CHILDREN); - av_dict_free(&opts); - } - - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy) - choose_sample_fmt(st, codec); - else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy) - choose_pixel_fmt(st, st->codec, codec, st->codecpar->format); - avcodec_copy_context(ost->enc_ctx, st->codec); - if (enc_config) - av_dict_parse_string(&ost->encoder_opts, enc_config, "=", ",", 0); - } - - avformat_close_input(&ic); - return err; -} - static void init_output_filter(OutputFilter *ofilter, OptionsContext *o, AVFormatContext *oc) { @@ -2092,7 +2054,6 @@ static int open_output_file(OptionsContext *o, const char *filename) { AVFormatContext *oc; int i, j, err; - AVOutputFormat *file_oformat; OutputFile *of; OutputStream *ost; InputStream *ist; @@ -2141,7 +2102,6 @@ static int open_output_file(OptionsContext *o, const char *filename) if (o->recording_time != INT64_MAX) oc->duration = o->recording_time; - file_oformat= oc->oformat; oc->interrupt_callback = int_cb; e = av_dict_get(o->g->format_opts, "fflags", NULL, 0); @@ -2149,6 +2109,10 @@ static int open_output_file(OptionsContext *o, const char *filename) const AVOption *o = av_opt_find(oc, "fflags", NULL, 0, 0); av_opt_eval_flags(oc, o, e->value, &format_flags); } + if (o->bitexact) { + format_flags |= AVFMT_FLAG_BITEXACT; + oc->flags |= AVFMT_FLAG_BITEXACT; + } /* create streams for all unlabeled output pads */ for (i = 0; i < nb_filtergraphs; i++) { @@ -2168,47 +2132,7 @@ static int open_output_file(OptionsContext *o, const char *filename) } } - /* ffserver seeking with date=... needs a date reference */ - if (!strcmp(file_oformat->name, "ffm") && - !(format_flags & AVFMT_FLAG_BITEXACT) && - av_strstart(filename, "http:", NULL)) { - int err = parse_option(o, "metadata", "creation_time=now", options); - if (err < 0) { - print_error(filename, err); - exit_program(1); - } - } - - if (!strcmp(file_oformat->name, "ffm") && !override_ffserver && - av_strstart(filename, "http:", NULL)) { - int j; - /* special case for files sent to ffserver: we get the stream - parameters from ffserver */ - int err = read_ffserver_streams(o, oc, filename); - if (err < 0) { - print_error(filename, err); - exit_program(1); - } - for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) { - ost = output_streams[j]; - for (i = 0; i < nb_input_streams; i++) { - ist = input_streams[i]; - if(ist->st->codecpar->codec_type == ost->st->codecpar->codec_type){ - ost->sync_ist= ist; - ost->source_index= i; - if(ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull"); - if(ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null"); - ist->discard = 0; - ist->st->discard = ist->user_set_discard; - break; - } - } - if(!ost->sync_ist){ - av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codecpar->codec_type)); - exit_program(1); - } - } - } else if (!o->nb_stream_maps) { + if (!o->nb_stream_maps) { char *subtitle_codec_name = NULL; /* pick the "best" stream of each type */ @@ -3404,7 +3328,7 @@ const OptionDef options[] = { OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) }, "record or transcode \"duration\" seconds of audio/video", "duration" }, - { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(stop_time) }, + { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(stop_time) }, "record or transcode stop time", "time_stop" }, { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) }, "set the limit file size in bytes", "limit_size" }, @@ -3472,6 +3396,9 @@ const OptionDef options[] = { { "shortest", OPT_BOOL | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(shortest) }, "finish encoding within shortest input" }, + { "bitexact", OPT_BOOL | OPT_EXPERT | OPT_OFFSET | + OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(bitexact) }, + "bitexact mode" }, { "apad", OPT_STRING | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(apad) }, "audio pad", "" }, @@ -3632,7 +3559,7 @@ const OptionDef options[] = { { "hwaccel_output_format", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_output_formats) }, "select output format used with HW accelerated decoding", "format" }, -#if CONFIG_VDA || CONFIG_VIDEOTOOLBOX +#if CONFIG_VIDEOTOOLBOX { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" }, #endif { "hwaccels", OPT_EXIT, { .func_arg = show_hwaccels }, @@ -3640,8 +3567,6 @@ const OptionDef options[] = { { "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) }, "automatically insert correct rotate filters" }, - { "hwaccel_lax_profile_check", OPT_BOOL | OPT_EXPERT, { &hwaccel_lax_profile_check}, - "attempt to decode anyway if HW accelerated decoder's supported profiles do not exactly match the stream" }, /* audio options */ { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames }, @@ -3699,8 +3624,6 @@ const OptionDef options[] = { "set the maximum demux-decode delay", "seconds" }, { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) }, "set the initial demux-decode delay", "seconds" }, - { "override_ffserver", OPT_BOOL | OPT_EXPERT | OPT_OUTPUT, { &override_ffserver }, - "override the options from ffserver", "" }, { "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_sdp_file }, "specify a file in which to print sdp information", "file" }, diff --git a/fftools/ffmpeg_videotoolbox.c b/fftools/ffmpeg_videotoolbox.c index e9039654b..b820aec01 100644 --- a/fftools/ffmpeg_videotoolbox.c +++ b/fftools/ffmpeg_videotoolbox.c @@ -23,12 +23,7 @@ #endif #include "libavcodec/avcodec.h" -#if CONFIG_VDA -# include "libavcodec/vda.h" -#endif -#if CONFIG_VIDEOTOOLBOX -# include "libavcodec/videotoolbox.h" -#endif +#include "libavcodec/videotoolbox.h" #include "libavutil/imgutils.h" #include "ffmpeg.h" @@ -114,15 +109,7 @@ static void videotoolbox_uninit(AVCodecContext *s) av_frame_free(&vt->tmp_frame); - if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) { -#if CONFIG_VIDEOTOOLBOX - av_videotoolbox_default_free(s); -#endif - } else { -#if CONFIG_VDA - av_vda_default_free(s); -#endif - } + av_videotoolbox_default_free(s); av_freep(&ist->hwaccel_ctx); } @@ -147,8 +134,7 @@ int videotoolbox_init(AVCodecContext *s) goto fail; } - if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) { -#if CONFIG_VIDEOTOOLBOX + // TODO: reindent if (!videotoolbox_pixfmt) { ret = av_videotoolbox_default_init(s); } else { @@ -166,31 +152,8 @@ int videotoolbox_init(AVCodecContext *s) ret = av_videotoolbox_default_init2(s, vtctx); CFRelease(pixfmt_str); } -#endif - } else { -#if CONFIG_VDA - if (!videotoolbox_pixfmt) { - ret = av_vda_default_init(s); - } else { - AVVDAContext *vdactx = av_vda_alloc_context(); - CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault, - videotoolbox_pixfmt, - kCFStringEncodingUTF8); -#if HAVE_UTGETOSTYPEFROMSTRING - vdactx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str); -#else - av_log(s, loglevel, "UTGetOSTypeFromString() is not available " - "on this platform, %s pixel format can not be honored from " - "the command line\n", videotoolbox_pixfmt); -#endif - ret = av_vda_default_init2(s, vdactx); - CFRelease(pixfmt_str); - } -#endif - } if (ret < 0) { - av_log(NULL, loglevel, - "Error creating %s decoder.\n", ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX ? "Videotoolbox" : "VDA"); + av_log(NULL, loglevel, "Error creating Videotoolbox decoder.\n"); goto fail; } diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 9f7774613..9bfa3e6ce 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -361,6 +361,8 @@ static AVPacket flush_pkt; static SDL_Window *window; static SDL_Renderer *renderer; +static SDL_RendererInfo renderer_info = {0}; +static SDL_AudioDeviceID audio_dev; static const struct TextureFormatEntry { enum AVPixelFormat format; @@ -607,7 +609,7 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) { if (ret >= 0) { AVRational tb = (AVRational){1, frame->sample_rate}; if (frame->pts != AV_NOPTS_VALUE) - frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb); + frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb); else if (d->next_pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb); if (frame->pts != AV_NOPTS_VALUE) { @@ -1191,7 +1193,7 @@ static void stream_component_close(VideoState *is, int stream_index) switch (codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: decoder_abort(&is->auddec, &is->sampq); - SDL_CloseAudio(); + SDL_CloseAudioDevice(audio_dev); decoder_destroy(&is->auddec); swr_free(&is->swr_ctx); av_freep(&is->audio_buf1); @@ -1282,7 +1284,6 @@ static void do_exit(VideoState *is) SDL_DestroyRenderer(renderer); if (window) SDL_DestroyWindow(window); - av_lockmgr_register(NULL); uninit_opts(); #if CONFIG_AVFILTER av_freep(&vfilters_list); @@ -1320,38 +1321,15 @@ static int video_open(VideoState *is) h = default_height; } - if (!window) { - int flags = SDL_WINDOW_SHOWN; - if (!window_title) - window_title = input_filename; - if (is_full_screen) - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - if (borderless) - flags |= SDL_WINDOW_BORDERLESS; - else - flags |= SDL_WINDOW_RESIZABLE; - window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - if (window) { - SDL_RendererInfo info; - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (!renderer) { - av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); - renderer = SDL_CreateRenderer(window, -1, 0); - } - if (renderer) { - if (!SDL_GetRendererInfo(renderer, &info)) - av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", info.name); - } - } - } else { - SDL_SetWindowSize(window, w, h); - } + if (!window_title) + window_title = input_filename; + SDL_SetWindowTitle(window, window_title); - if (!window || !renderer) { - av_log(NULL, AV_LOG_FATAL, "SDL: could not set video mode - exiting\n"); - do_exit(is); - } + SDL_SetWindowSize(window, w, h); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + if (is_full_screen) + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL_ShowWindow(window); is->width = w; is->height = h; @@ -1362,7 +1340,7 @@ static int video_open(VideoState *is) /* display the current picture, if any */ static void video_display(VideoState *is) { - if (!window) + if (!is->width) video_open(is); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); @@ -1850,10 +1828,18 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c AVCodecParameters *codecpar = is->video_st->codecpar; AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL); AVDictionaryEntry *e = NULL; - int i; + int nb_pix_fmts = 0; + int i, j; - for (i = 0; i < FF_ARRAY_ELEMS(pix_fmts); i++) - pix_fmts[i] = sdl_texture_format_map[i].format; + for (i = 0; i < renderer_info.num_texture_formats; i++) { + for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; j++) { + if (renderer_info.texture_formats[i] == sdl_texture_format_map[j].texture_fmt) { + pix_fmts[nb_pix_fmts++] = sdl_texture_format_map[j].format; + break; + } + } + } + pix_fmts[nb_pix_fmts] = AV_PIX_FMT_NONE; while ((e = av_dict_get(sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) { if (!strcmp(e->key, "sws_flags")) { @@ -2465,7 +2451,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) else { memset(stream, 0, len1); if (!is->muted && is->audio_buf) - SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume); + SDL_MixAudioFormat(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, is->audio_volume); } len -= len1; stream += len1; @@ -2510,7 +2496,7 @@ static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC)); wanted_spec.callback = sdl_audio_callback; wanted_spec.userdata = opaque; - while (SDL_OpenAudio(&wanted_spec, &spec) < 0) { + while (!(audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) { av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n", wanted_spec.channels, wanted_spec.freq, SDL_GetError()); wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)]; @@ -2576,7 +2562,7 @@ static int stream_component_open(VideoState *is, int stream_index) ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar); if (ret < 0) goto fail; - av_codec_set_pkt_timebase(avctx, ic->streams[stream_index]->time_base); + avctx->pkt_timebase = ic->streams[stream_index]->time_base; codec = avcodec_find_decoder(avctx->codec_id); @@ -2597,22 +2583,15 @@ static int stream_component_open(VideoState *is, int stream_index) } avctx->codec_id = codec->id; - if(stream_lowres > av_codec_get_max_lowres(codec)){ + if (stream_lowres > codec->max_lowres) { av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n", - av_codec_get_max_lowres(codec)); - stream_lowres = av_codec_get_max_lowres(codec); + codec->max_lowres); + stream_lowres = codec->max_lowres; } - av_codec_set_lowres(avctx, stream_lowres); + avctx->lowres = stream_lowres; -#if FF_API_EMU_EDGE - if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif if (fast) avctx->flags2 |= AV_CODEC_FLAG2_FAST; -#if FF_API_EMU_EDGE - if(codec->capabilities & AV_CODEC_CAP_DR1) - avctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec); if (!av_dict_get(opts, "threads", NULL, 0)) @@ -2680,7 +2659,7 @@ static int stream_component_open(VideoState *is, int stream_index) } if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0) goto out; - SDL_PauseAudio(0); + SDL_PauseAudioDevice(audio_dev, 0); break; case AVMEDIA_TYPE_VIDEO: is->video_stream = stream_index; @@ -3661,27 +3640,6 @@ void show_help_default(const char *opt, const char *arg) ); } -static int lockmgr(void **mtx, enum AVLockOp op) -{ - switch(op) { - case AV_LOCK_CREATE: - *mtx = SDL_CreateMutex(); - if(!*mtx) { - av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); - return 1; - } - return 0; - case AV_LOCK_OBTAIN: - return !!SDL_LockMutex(*mtx); - case AV_LOCK_RELEASE: - return !!SDL_UnlockMutex(*mtx); - case AV_LOCK_DESTROY: - SDL_DestroyMutex(*mtx); - return 0; - } - return 1; -} - /* Called from the main */ int main(int argc, char **argv) { @@ -3743,14 +3701,34 @@ int main(int argc, char **argv) SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE); SDL_EventState(SDL_USEREVENT, SDL_IGNORE); - if (av_lockmgr_register(lockmgr)) { - av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n"); - do_exit(NULL); - } - av_init_packet(&flush_pkt); flush_pkt.data = (uint8_t *)&flush_pkt; + if (!display_disable) { + int flags = SDL_WINDOW_HIDDEN; + if (borderless) + flags |= SDL_WINDOW_BORDERLESS; + else + flags |= SDL_WINDOW_RESIZABLE; + window = SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width, default_height, flags); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + if (window) { + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!renderer) { + av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); + renderer = SDL_CreateRenderer(window, -1, 0); + } + if (renderer) { + if (!SDL_GetRendererInfo(renderer, &renderer_info)) + av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", renderer_info.name); + } + } + if (!window || !renderer || !renderer_info.num_texture_formats) { + av_log(NULL, AV_LOG_FATAL, "Failed to create window or renderer: %s", SDL_GetError()); + do_exit(NULL); + } + } + is = stream_open(input_filename, file_iformat); if (!is) { av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n"); diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index b2e8949d9..0e7a77151 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -2792,7 +2792,7 @@ static int show_format(WriterContext *w, InputFile *ifile) else print_str_opt("size", "N/A"); if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str); else print_str_opt("bit_rate", "N/A"); - print_int("probe_score", av_format_get_probe_score(fmt_ctx)); + print_int("probe_score", fmt_ctx->probe_score); if (do_show_format_tags) ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); @@ -2828,8 +2828,6 @@ static int open_input_file(InputFile *ifile, const char *filename) exit_program(1); } - fmt_ctx->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); scan_all_pmts_set = 1; @@ -2912,7 +2910,7 @@ static int open_input_file(InputFile *ifile, const char *filename) av_dict_set(&codec_opts, "threads", "1", 0); } - av_codec_set_pkt_timebase(ist->dec_ctx, stream->time_base); + ist->dec_ctx->pkt_timebase = stream->time_base; ist->dec_ctx->framerate = stream->avg_frame_rate; if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) { diff --git a/fftools/ffserver.c b/fftools/ffserver.c deleted file mode 100644 index d4885dfa0..000000000 --- a/fftools/ffserver.c +++ /dev/null @@ -1,4026 +0,0 @@ -/* - * 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 - * multiple format streaming server based on the FFmpeg libraries - */ - -#include "config.h" -#if !HAVE_CLOSESOCKET -#define closesocket close -#endif -#include -#include -#include -#include "libavformat/avformat.h" -/* FIXME: those are internal headers, ffserver _really_ shouldn't use them */ -#include "libavformat/rtpproto.h" -#include "libavformat/rtsp.h" -#include "libavformat/avio_internal.h" -#include "libavformat/internal.h" - -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" -#include "libavutil/lfg.h" -#include "libavutil/dict.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/mathematics.h" -#include "libavutil/random_seed.h" -#include "libavutil/rational.h" -#include "libavutil/parseutils.h" -#include "libavutil/opt.h" -#include "libavutil/time.h" - -#include -#if HAVE_UNISTD_H -#include -#endif -#include -#include -#if HAVE_POLL_H -#include -#endif -#include -#include -#include -#include - -#include "cmdutils.h" -#include "ffserver_config.h" - -#define PATH_LENGTH 1024 - -const char program_name[] = "ffserver"; -const int program_birth_year = 2000; - -static const OptionDef options[]; - -enum HTTPState { - HTTPSTATE_WAIT_REQUEST, - HTTPSTATE_SEND_HEADER, - HTTPSTATE_SEND_DATA_HEADER, - HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */ - HTTPSTATE_SEND_DATA_TRAILER, - HTTPSTATE_RECEIVE_DATA, - HTTPSTATE_WAIT_FEED, /* wait for data from the feed */ - HTTPSTATE_READY, - - RTSPSTATE_WAIT_REQUEST, - RTSPSTATE_SEND_REPLY, - RTSPSTATE_SEND_PACKET, -}; - -static const char * const http_state[] = { - "HTTP_WAIT_REQUEST", - "HTTP_SEND_HEADER", - - "SEND_DATA_HEADER", - "SEND_DATA", - "SEND_DATA_TRAILER", - "RECEIVE_DATA", - "WAIT_FEED", - "READY", - - "RTSP_WAIT_REQUEST", - "RTSP_SEND_REPLY", - "RTSP_SEND_PACKET", -}; - -#define IOBUFFER_INIT_SIZE 8192 - -/* timeouts are in ms */ -#define HTTP_REQUEST_TIMEOUT (15 * 1000) -#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000) - -#define SYNC_TIMEOUT (10 * 1000) - -typedef struct RTSPActionServerSetup { - uint32_t ipaddr; - char transport_option[512]; -} RTSPActionServerSetup; - -typedef struct { - int64_t count1, count2; - int64_t time1, time2; -} DataRateData; - -/* context associated with one connection */ -typedef struct HTTPContext { - enum HTTPState state; - int fd; /* socket file descriptor */ - struct sockaddr_in from_addr; /* origin */ - struct pollfd *poll_entry; /* used when polling */ - int64_t timeout; - uint8_t *buffer_ptr, *buffer_end; - int http_error; - int post; - int chunked_encoding; - int chunk_size; /* 0 if it needs to be read */ - struct HTTPContext *next; - int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */ - int64_t data_count; - /* feed input */ - int feed_fd; - /* input format handling */ - AVFormatContext *fmt_in; - int64_t start_time; /* In milliseconds - this wraps fairly often */ - int64_t first_pts; /* initial pts value */ - int64_t cur_pts; /* current pts value from the stream in us */ - int64_t cur_frame_duration; /* duration of the current frame in us */ - int cur_frame_bytes; /* output frame size, needed to compute - the time at which we send each - packet */ - int pts_stream_index; /* stream we choose as clock reference */ - int64_t cur_clock; /* current clock reference value in us */ - /* output format handling */ - struct FFServerStream *stream; - /* -1 is invalid stream */ - int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ - int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ - int switch_pending; - AVFormatContext *pfmt_ctx; /* instance of FFServerStream for one user */ - int last_packet_sent; /* true if last data packet was sent */ - int suppress_log; - DataRateData datarate; - int wmp_client_id; - char protocol[16]; - char method[16]; - char url[128]; - char clean_url[128*7]; - int buffer_size; - uint8_t *buffer; - int is_packetized; /* if true, the stream is packetized */ - int packet_stream_index; /* current stream for output in state machine */ - - /* RTSP state specific */ - uint8_t *pb_buffer; /* XXX: use that in all the code */ - AVIOContext *pb; - int seq; /* RTSP sequence number */ - - /* RTP state specific */ - enum RTSPLowerTransport rtp_protocol; - char session_id[32]; /* session id */ - AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS]; - - /* RTP/UDP specific */ - URLContext *rtp_handles[FFSERVER_MAX_STREAMS]; - - /* RTP/TCP specific */ - struct HTTPContext *rtsp_c; - uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end; -} HTTPContext; - -static HTTPContext *first_http_ctx; - -static FFServerConfig config = { - .nb_max_http_connections = 2000, - .nb_max_connections = 5, - .max_bandwidth = 1000, - .use_defaults = 1, -}; - -static void new_connection(int server_fd, int is_rtsp); -static void close_connection(HTTPContext *c); - -/* HTTP handling */ -static int handle_connection(HTTPContext *c); -static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream); -static void compute_status(HTTPContext *c); -static int open_input_stream(HTTPContext *c, const char *info); -static int http_parse_request(HTTPContext *c); -static int http_send_data(HTTPContext *c); -static int http_start_receive_data(HTTPContext *c); -static int http_receive_data(HTTPContext *c); - -/* RTSP handling */ -static int rtsp_parse_request(HTTPContext *c); -static void rtsp_cmd_describe(HTTPContext *c, const char *url); -static void rtsp_cmd_options(HTTPContext *c, const char *url); -static void rtsp_cmd_setup(HTTPContext *c, const char *url, - RTSPMessageHeader *h); -static void rtsp_cmd_play(HTTPContext *c, const char *url, - RTSPMessageHeader *h); -static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, - RTSPMessageHeader *h, int pause_only); - -/* SDP handling */ -static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer, - struct in_addr my_ip); - -/* RTP handling */ -static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, - FFServerStream *stream, - const char *session_id, - enum RTSPLowerTransport rtp_protocol); -static int rtp_new_av_stream(HTTPContext *c, - int stream_index, struct sockaddr_in *dest_addr, - HTTPContext *rtsp_c); -/* utils */ -static size_t htmlencode (const char *src, char **dest); -static inline void cp_html_entity (char *buffer, const char *entity); -static inline int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream); - -static const char *my_program_name; - -static int no_launch; -static int need_to_start_children; - -/* maximum number of simultaneous HTTP connections */ -static unsigned int nb_connections; - -static uint64_t current_bandwidth; - -/* Making this global saves on passing it around everywhere */ -static int64_t cur_time; - -static AVLFG random_state; - -static FILE *logfile = NULL; - -static void unlayer_stream(AVStream *st, LayeredAVStream *lst) -{ - avcodec_free_context(&st->codec); - avcodec_parameters_free(&st->codecpar); -#define COPY(a) st->a = lst->a; - COPY(index) - COPY(id) - COPY(codec) - COPY(codecpar) - COPY(time_base) - COPY(pts_wrap_bits) - COPY(sample_aspect_ratio) - COPY(recommended_encoder_configuration) -} - -static inline void cp_html_entity (char *buffer, const char *entity) { - if (!buffer || !entity) - return; - while (*entity) - *buffer++ = *entity++; -} - -/** - * Substitutes known conflicting chars on a text string with - * their corresponding HTML entities. - * - * Returns the number of bytes in the 'encoded' representation - * not including the terminating NUL. - */ -static size_t htmlencode (const char *src, char **dest) { - const char *amp = "&"; - const char *lt = "<"; - const char *gt = ">"; - const char *start; - char *tmp; - size_t final_size = 0; - - if (!src) - return 0; - - start = src; - - /* Compute needed dest size */ - while (*src != '\0') { - switch(*src) { - case 38: /* & */ - final_size += 5; - break; - case 60: /* < */ - case 62: /* > */ - final_size += 4; - break; - default: - final_size++; - } - src++; - } - - src = start; - *dest = av_mallocz(final_size + 1); - if (!*dest) - return 0; - - /* Build dest */ - tmp = *dest; - while (*src != '\0') { - switch(*src) { - case 38: /* & */ - cp_html_entity (tmp, amp); - tmp += 5; - break; - case 60: /* < */ - cp_html_entity (tmp, lt); - tmp += 4; - break; - case 62: /* > */ - cp_html_entity (tmp, gt); - tmp += 4; - break; - default: - *tmp = *src; - tmp += 1; - } - src++; - } - *tmp = '\0'; - - return final_size; -} - -static int64_t ffm_read_write_index(int fd) -{ - uint8_t buf[8]; - - if (lseek(fd, 8, SEEK_SET) < 0) - return AVERROR(EIO); - if (read(fd, buf, 8) != 8) - return AVERROR(EIO); - return AV_RB64(buf); -} - -static int ffm_write_write_index(int fd, int64_t pos) -{ - uint8_t buf[8]; - int i; - - for(i=0;i<8;i++) - buf[i] = (pos >> (56 - i * 8)) & 0xff; - if (lseek(fd, 8, SEEK_SET) < 0) - goto bail_eio; - if (write(fd, buf, 8) != 8) - goto bail_eio; - - return 8; - -bail_eio: - return AVERROR(EIO); -} - -static void ffm_set_write_index(AVFormatContext *s, int64_t pos, - int64_t file_size) -{ - av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN); - av_opt_set_int(s, "ffm_write_index", pos, AV_OPT_SEARCH_CHILDREN); - av_opt_set_int(s, "ffm_file_size", file_size, AV_OPT_SEARCH_CHILDREN); -} - -static char *ctime1(char *buf2, size_t buf_size) -{ - time_t ti; - char *p; - - ti = time(NULL); - p = ctime(&ti); - if (!p || !*p) { - *buf2 = '\0'; - return buf2; - } - av_strlcpy(buf2, p, buf_size); - p = buf2 + strlen(buf2) - 1; - if (*p == '\n') - *p = '\0'; - return buf2; -} - -static void http_vlog(const char *fmt, va_list vargs) -{ - static int print_prefix = 1; - char buf[32]; - - if (!logfile) - return; - - if (print_prefix) { - ctime1(buf, sizeof(buf)); - fprintf(logfile, "%s ", buf); - } - print_prefix = strstr(fmt, "\n") != NULL; - vfprintf(logfile, fmt, vargs); - fflush(logfile); -} - -#ifdef __GNUC__ -__attribute__ ((format (printf, 1, 2))) -#endif -static void http_log(const char *fmt, ...) -{ - va_list vargs; - va_start(vargs, fmt); - http_vlog(fmt, vargs); - va_end(vargs); -} - -static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs) -{ - static int print_prefix = 1; - AVClass *avc = ptr ? *(AVClass**)ptr : NULL; - if (level > av_log_get_level()) - return; - if (print_prefix && avc) - http_log("[%s @ %p]", avc->item_name(ptr), ptr); - print_prefix = strstr(fmt, "\n") != NULL; - http_vlog(fmt, vargs); -} - -static void log_connection(HTTPContext *c) -{ - if (c->suppress_log) - return; - - http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n", - inet_ntoa(c->from_addr.sin_addr), c->method, c->url, - c->protocol, (c->http_error ? c->http_error : 200), c->data_count); -} - -static void update_datarate(DataRateData *drd, int64_t count) -{ - if (!drd->time1 && !drd->count1) { - drd->time1 = drd->time2 = cur_time; - drd->count1 = drd->count2 = count; - } else if (cur_time - drd->time2 > 5000) { - drd->time1 = drd->time2; - drd->count1 = drd->count2; - drd->time2 = cur_time; - drd->count2 = count; - } -} - -/* In bytes per second */ -static int compute_datarate(DataRateData *drd, int64_t count) -{ - if (cur_time == drd->time1) - return 0; - - return ((count - drd->count1) * 1000) / (cur_time - drd->time1); -} - - -static void start_children(FFServerStream *feed) -{ - char *pathname; - char *slash; - int i; - size_t cmd_length; - - if (no_launch) - return; - - cmd_length = strlen(my_program_name); - - /** - * FIXME: WIP Safeguard. Remove after clearing all harcoded - * '1024' path lengths - */ - if (cmd_length > PATH_LENGTH - 1) { - http_log("Could not start children. Command line: '%s' exceeds " - "path length limit (%d)\n", my_program_name, PATH_LENGTH); - return; - } - - slash = strrchr(my_program_name, '/'); - if (!slash) { - pathname = av_mallocz(sizeof("ffmpeg")); - } else { - pathname = av_mallocz(slash - my_program_name + sizeof("ffmpeg")); - if (pathname != NULL) { - memcpy(pathname, my_program_name, slash - my_program_name); - } - } - if (!pathname) { - http_log("Could not allocate memory for children cmd line\n"); - return; - } - /* use "ffmpeg" in the path of current program. Ignore user provided path */ - - strcat(pathname, "ffmpeg"); - - for (; feed; feed = feed->next) { - - if (!feed->child_argv || feed->pid) - continue; - - feed->pid_start = time(0); - - feed->pid = fork(); - if (feed->pid < 0) { - http_log("Unable to create children: %s\n", strerror(errno)); - av_free (pathname); - exit(EXIT_FAILURE); - } - - if (feed->pid) - continue; - - /* In child */ - - http_log("Launch command line: "); - http_log("%s ", pathname); - - for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++) - http_log("%s ", feed->child_argv[i]); - http_log("\n"); - - for (i = 3; i < 256; i++) - close(i); - - if (!config.debug) { - if (!freopen("/dev/null", "r", stdin)) - http_log("failed to redirect STDIN to /dev/null\n;"); - if (!freopen("/dev/null", "w", stdout)) - http_log("failed to redirect STDOUT to /dev/null\n;"); - if (!freopen("/dev/null", "w", stderr)) - http_log("failed to redirect STDERR to /dev/null\n;"); - } - - signal(SIGPIPE, SIG_DFL); - execvp(pathname, feed->child_argv); - av_free (pathname); - _exit(1); - } - av_free (pathname); -} - -/* open a listening socket */ -static int socket_open_listen(struct sockaddr_in *my_addr) -{ - int server_fd, tmp; - - server_fd = socket(AF_INET,SOCK_STREAM,0); - if (server_fd < 0) { - perror ("socket"); - return -1; - } - - tmp = 1; - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) - av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n"); - - my_addr->sin_family = AF_INET; - if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) { - char bindmsg[32]; - snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", - ntohs(my_addr->sin_port)); - perror (bindmsg); - goto fail; - } - - if (listen (server_fd, 5) < 0) { - perror ("listen"); - goto fail; - } - - if (ff_socket_nonblock(server_fd, 1) < 0) - av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n"); - - return server_fd; - -fail: - closesocket(server_fd); - return -1; -} - -/* start all multicast streams */ -static void start_multicast(void) -{ - FFServerStream *stream; - char session_id[32]; - HTTPContext *rtp_c; - struct sockaddr_in dest_addr = {0}; - int default_port, stream_index; - unsigned int random0, random1; - - default_port = 6000; - for(stream = config.first_stream; stream; stream = stream->next) { - - if (!stream->is_multicast) - continue; - - random0 = av_lfg_get(&random_state); - random1 = av_lfg_get(&random_state); - - /* open the RTP connection */ - snprintf(session_id, sizeof(session_id), "%08x%08x", random0, random1); - - /* choose a port if none given */ - if (stream->multicast_port == 0) { - stream->multicast_port = default_port; - default_port += 100; - } - - dest_addr.sin_family = AF_INET; - dest_addr.sin_addr = stream->multicast_ip; - dest_addr.sin_port = htons(stream->multicast_port); - - rtp_c = rtp_new_connection(&dest_addr, stream, session_id, - RTSP_LOWER_TRANSPORT_UDP_MULTICAST); - if (!rtp_c) - continue; - - if (open_input_stream(rtp_c, "") < 0) { - http_log("Could not open input stream for stream '%s'\n", - stream->filename); - continue; - } - - /* open each RTP stream */ - for(stream_index = 0; stream_index < stream->nb_streams; - stream_index++) { - dest_addr.sin_port = htons(stream->multicast_port + - 2 * stream_index); - if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0) - continue; - - http_log("Could not open output stream '%s/streamid=%d'\n", - stream->filename, stream_index); - exit(1); - } - - rtp_c->state = HTTPSTATE_SEND_DATA; - } -} - -/* main loop of the HTTP server */ -static int http_server(void) -{ - int server_fd = 0, rtsp_server_fd = 0; - int ret, delay; - struct pollfd *poll_table, *poll_entry; - HTTPContext *c, *c_next; - - poll_table = av_mallocz_array(config.nb_max_http_connections + 2, - sizeof(*poll_table)); - if(!poll_table) { - http_log("Impossible to allocate a poll table handling %d " - "connections.\n", config.nb_max_http_connections); - return -1; - } - - if (config.http_addr.sin_port) { - server_fd = socket_open_listen(&config.http_addr); - if (server_fd < 0) - goto quit; - } - - if (config.rtsp_addr.sin_port) { - rtsp_server_fd = socket_open_listen(&config.rtsp_addr); - if (rtsp_server_fd < 0) { - closesocket(server_fd); - goto quit; - } - } - - if (!rtsp_server_fd && !server_fd) { - http_log("HTTP and RTSP disabled.\n"); - goto quit; - } - - http_log("FFserver started.\n"); - - start_children(config.first_feed); - - start_multicast(); - - for(;;) { - poll_entry = poll_table; - if (server_fd) { - poll_entry->fd = server_fd; - poll_entry->events = POLLIN; - poll_entry++; - } - if (rtsp_server_fd) { - poll_entry->fd = rtsp_server_fd; - poll_entry->events = POLLIN; - poll_entry++; - } - - /* wait for events on each HTTP handle */ - c = first_http_ctx; - delay = 1000; - while (c) { - int fd; - fd = c->fd; - switch(c->state) { - case HTTPSTATE_SEND_HEADER: - case RTSPSTATE_SEND_REPLY: - case RTSPSTATE_SEND_PACKET: - c->poll_entry = poll_entry; - poll_entry->fd = fd; - poll_entry->events = POLLOUT; - poll_entry++; - break; - case HTTPSTATE_SEND_DATA_HEADER: - case HTTPSTATE_SEND_DATA: - case HTTPSTATE_SEND_DATA_TRAILER: - if (!c->is_packetized) { - /* for TCP, we output as much as we can - * (may need to put a limit) */ - c->poll_entry = poll_entry; - poll_entry->fd = fd; - poll_entry->events = POLLOUT; - poll_entry++; - } else { - /* when ffserver is doing the timing, we work by - * looking at which packet needs to be sent every - * 10 ms (one tick wait XXX: 10 ms assumed) */ - if (delay > 10) - delay = 10; - } - break; - case HTTPSTATE_WAIT_REQUEST: - case HTTPSTATE_RECEIVE_DATA: - case HTTPSTATE_WAIT_FEED: - case RTSPSTATE_WAIT_REQUEST: - /* need to catch errors */ - c->poll_entry = poll_entry; - poll_entry->fd = fd; - poll_entry->events = POLLIN;/* Maybe this will work */ - poll_entry++; - break; - default: - c->poll_entry = NULL; - break; - } - c = c->next; - } - - /* wait for an event on one connection. We poll at least every - * second to handle timeouts */ - do { - ret = poll(poll_table, poll_entry - poll_table, delay); - if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) { - goto quit; - } - } while (ret < 0); - - cur_time = av_gettime() / 1000; - - if (need_to_start_children) { - need_to_start_children = 0; - start_children(config.first_feed); - } - - /* now handle the events */ - for(c = first_http_ctx; c; c = c_next) { - c_next = c->next; - if (handle_connection(c) < 0) { - log_connection(c); - /* close and free the connection */ - close_connection(c); - } - } - - poll_entry = poll_table; - if (server_fd) { - /* new HTTP connection request ? */ - if (poll_entry->revents & POLLIN) - new_connection(server_fd, 0); - poll_entry++; - } - if (rtsp_server_fd) { - /* new RTSP connection request ? */ - if (poll_entry->revents & POLLIN) - new_connection(rtsp_server_fd, 1); - } - } - -quit: - av_free(poll_table); - return -1; -} - -/* start waiting for a new HTTP/RTSP request */ -static void start_wait_request(HTTPContext *c, int is_rtsp) -{ - c->buffer_ptr = c->buffer; - c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */ - - c->state = is_rtsp ? RTSPSTATE_WAIT_REQUEST : HTTPSTATE_WAIT_REQUEST; - c->timeout = cur_time + - (is_rtsp ? RTSP_REQUEST_TIMEOUT : HTTP_REQUEST_TIMEOUT); -} - -static void http_send_too_busy_reply(int fd) -{ - char buffer[400]; - int len = snprintf(buffer, sizeof(buffer), - "HTTP/1.0 503 Server too busy\r\n" - "Content-type: text/html\r\n" - "\r\n" - "\n" - "Too busy\r\n" - "

The server is too busy to serve your request at " - "this time.

\r\n" - "

The number of current connections is %u, and this " - "exceeds the limit of %u.

\r\n" - "\r\n", - nb_connections, config.nb_max_connections); - av_assert0(len < sizeof(buffer)); - if (send(fd, buffer, len, 0) < len) - av_log(NULL, AV_LOG_WARNING, - "Could not send too-busy reply, send() failed\n"); -} - - -static void new_connection(int server_fd, int is_rtsp) -{ - struct sockaddr_in from_addr; - socklen_t len; - int fd; - HTTPContext *c = NULL; - - len = sizeof(from_addr); - fd = accept(server_fd, (struct sockaddr *)&from_addr, - &len); - if (fd < 0) { - http_log("error during accept %s\n", strerror(errno)); - return; - } - if (ff_socket_nonblock(fd, 1) < 0) - av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n"); - - if (nb_connections >= config.nb_max_connections) { - http_send_too_busy_reply(fd); - goto fail; - } - - /* add a new connection */ - c = av_mallocz(sizeof(HTTPContext)); - if (!c) - goto fail; - - c->fd = fd; - c->poll_entry = NULL; - c->from_addr = from_addr; - c->buffer_size = IOBUFFER_INIT_SIZE; - c->buffer = av_malloc(c->buffer_size); - if (!c->buffer) - goto fail; - - c->next = first_http_ctx; - first_http_ctx = c; - nb_connections++; - - start_wait_request(c, is_rtsp); - - return; - - fail: - if (c) { - av_freep(&c->buffer); - av_free(c); - } - closesocket(fd); -} - -static void close_connection(HTTPContext *c) -{ - HTTPContext **cp, *c1; - int i, nb_streams; - AVFormatContext *ctx; - AVStream *st; - - /* remove connection from list */ - cp = &first_http_ctx; - while (*cp) { - c1 = *cp; - if (c1 == c) - *cp = c->next; - else - cp = &c1->next; - } - - /* remove references, if any (XXX: do it faster) */ - for(c1 = first_http_ctx; c1; c1 = c1->next) { - if (c1->rtsp_c == c) - c1->rtsp_c = NULL; - } - - /* remove connection associated resources */ - if (c->fd >= 0) - closesocket(c->fd); - if (c->fmt_in) { - /* close each frame parser */ - for(i=0;ifmt_in->nb_streams;i++) { - st = c->fmt_in->streams[i]; - if (st->codec->codec) - avcodec_close(st->codec); - } - avformat_close_input(&c->fmt_in); - } - - /* free RTP output streams if any */ - nb_streams = 0; - if (c->stream) - nb_streams = c->stream->nb_streams; - - for(i=0;irtp_ctx[i]; - if (ctx) { - av_write_trailer(ctx); - av_dict_free(&ctx->metadata); - av_freep(&ctx->streams[0]); - av_freep(&ctx); - } - ffurl_close(c->rtp_handles[i]); - } - - ctx = c->pfmt_ctx; - - if (ctx) { - if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) { - /* prepare header */ - if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) { - av_write_trailer(ctx); - av_freep(&c->pb_buffer); - avio_close_dyn_buf(ctx->pb, &c->pb_buffer); - } - } - for(i=0; inb_streams; i++) - av_freep(&ctx->streams[i]); - av_freep(&ctx->streams); - av_freep(&ctx->priv_data); - } - - if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE) - current_bandwidth -= c->stream->bandwidth; - - /* signal that there is no feed if we are the feeder socket */ - if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) { - c->stream->feed_opened = 0; - close(c->feed_fd); - } - - av_freep(&c->pb_buffer); - av_freep(&c->packet_buffer); - av_freep(&c->buffer); - av_free(c); - nb_connections--; -} - -static int handle_connection(HTTPContext *c) -{ - int len, ret; - uint8_t *ptr; - - switch(c->state) { - case HTTPSTATE_WAIT_REQUEST: - case RTSPSTATE_WAIT_REQUEST: - /* timeout ? */ - if ((c->timeout - cur_time) < 0) - return -1; - if (c->poll_entry->revents & (POLLERR | POLLHUP)) - return -1; - - /* no need to read if no events */ - if (!(c->poll_entry->revents & POLLIN)) - return 0; - /* read the data */ - read_loop: - if (!(len = recv(c->fd, c->buffer_ptr, 1, 0))) - return -1; - - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - return -1; - break; - } - /* search for end of request. */ - c->buffer_ptr += len; - ptr = c->buffer_ptr; - if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) || - (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) { - /* request found : parse it and reply */ - if (c->state == HTTPSTATE_WAIT_REQUEST) - ret = http_parse_request(c); - else - ret = rtsp_parse_request(c); - - if (ret < 0) - return -1; - } else if (ptr >= c->buffer_end) { - /* request too long: cannot do anything */ - return -1; - } else goto read_loop; - - break; - - case HTTPSTATE_SEND_HEADER: - if (c->poll_entry->revents & (POLLERR | POLLHUP)) - return -1; - - /* no need to write if no events */ - if (!(c->poll_entry->revents & POLLOUT)) - return 0; - len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) { - goto close_connection; - } - break; - } - c->buffer_ptr += len; - if (c->stream) - c->stream->bytes_served += len; - c->data_count += len; - if (c->buffer_ptr >= c->buffer_end) { - av_freep(&c->pb_buffer); - /* if error, exit */ - if (c->http_error) - return -1; - /* all the buffer was sent : synchronize to the incoming - * stream */ - c->state = HTTPSTATE_SEND_DATA_HEADER; - c->buffer_ptr = c->buffer_end = c->buffer; - } - break; - - case HTTPSTATE_SEND_DATA: - case HTTPSTATE_SEND_DATA_HEADER: - case HTTPSTATE_SEND_DATA_TRAILER: - /* for packetized output, we consider we can always write (the - * input streams set the speed). It may be better to verify - * that we do not rely too much on the kernel queues */ - if (!c->is_packetized) { - if (c->poll_entry->revents & (POLLERR | POLLHUP)) - return -1; - - /* no need to read if no events */ - if (!(c->poll_entry->revents & POLLOUT)) - return 0; - } - if (http_send_data(c) < 0) - return -1; - /* close connection if trailer sent */ - if (c->state == HTTPSTATE_SEND_DATA_TRAILER) - return -1; - /* Check if it is a single jpeg frame 123 */ - if (c->stream->single_frame && c->data_count > c->cur_frame_bytes && c->cur_frame_bytes > 0) { - close_connection(c); - } - break; - case HTTPSTATE_RECEIVE_DATA: - /* no need to read if no events */ - if (c->poll_entry->revents & (POLLERR | POLLHUP)) - return -1; - if (!(c->poll_entry->revents & POLLIN)) - return 0; - if (http_receive_data(c) < 0) - return -1; - break; - case HTTPSTATE_WAIT_FEED: - /* no need to read if no events */ - if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP)) - return -1; - - /* nothing to do, we'll be waken up by incoming feed packets */ - break; - - case RTSPSTATE_SEND_REPLY: - if (c->poll_entry->revents & (POLLERR | POLLHUP)) - goto close_connection; - /* no need to write if no events */ - if (!(c->poll_entry->revents & POLLOUT)) - return 0; - len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) { - goto close_connection; - } - break; - } - c->buffer_ptr += len; - c->data_count += len; - if (c->buffer_ptr >= c->buffer_end) { - /* all the buffer was sent : wait for a new request */ - av_freep(&c->pb_buffer); - start_wait_request(c, 1); - } - break; - case RTSPSTATE_SEND_PACKET: - if (c->poll_entry->revents & (POLLERR | POLLHUP)) { - av_freep(&c->packet_buffer); - return -1; - } - /* no need to write if no events */ - if (!(c->poll_entry->revents & POLLOUT)) - return 0; - len = send(c->fd, c->packet_buffer_ptr, - c->packet_buffer_end - c->packet_buffer_ptr, 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) { - /* error : close connection */ - av_freep(&c->packet_buffer); - return -1; - } - break; - } - c->packet_buffer_ptr += len; - if (c->packet_buffer_ptr >= c->packet_buffer_end) { - /* all the buffer was sent : wait for a new request */ - av_freep(&c->packet_buffer); - c->state = RTSPSTATE_WAIT_REQUEST; - } - break; - case HTTPSTATE_READY: - /* nothing to do */ - break; - default: - return -1; - } - return 0; - -close_connection: - av_freep(&c->pb_buffer); - return -1; -} - -static int extract_rates(char *rates, int ratelen, const char *request) -{ - const char *p; - - for (p = request; *p && *p != '\r' && *p != '\n'; ) { - if (av_strncasecmp(p, "Pragma:", 7) == 0) { - const char *q = p + 7; - - while (*q && *q != '\n' && av_isspace(*q)) - q++; - - if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) { - int stream_no; - int rate_no; - - q += 20; - - memset(rates, 0xff, ratelen); - - while (1) { - while (*q && *q != '\n' && *q != ':') - q++; - - if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) - break; - - stream_no--; - if (stream_no < ratelen && stream_no >= 0) - rates[stream_no] = rate_no; - - while (*q && *q != '\n' && !av_isspace(*q)) - q++; - } - - return 1; - } - } - p = strchr(p, '\n'); - if (!p) - break; - - p++; - } - - return 0; -} - -static int find_stream_in_feed(FFServerStream *feed, AVCodecParameters *codec, - int bit_rate) -{ - int i; - int best_bitrate = 100000000; - int best = -1; - - for (i = 0; i < feed->nb_streams; i++) { - AVCodecParameters *feed_codec = feed->streams[i]->codecpar; - - if (feed_codec->codec_id != codec->codec_id || - feed_codec->sample_rate != codec->sample_rate || - feed_codec->width != codec->width || - feed_codec->height != codec->height) - continue; - - /* Potential stream */ - - /* We want the fastest stream less than bit_rate, or the slowest - * faster than bit_rate - */ - - if (feed_codec->bit_rate <= bit_rate) { - if (best_bitrate > bit_rate || - feed_codec->bit_rate > best_bitrate) { - best_bitrate = feed_codec->bit_rate; - best = i; - } - continue; - } - if (feed_codec->bit_rate < best_bitrate) { - best_bitrate = feed_codec->bit_rate; - best = i; - } - } - return best; -} - -static int modify_current_stream(HTTPContext *c, char *rates) -{ - int i; - FFServerStream *req = c->stream; - int action_required = 0; - - /* Not much we can do for a feed */ - if (!req->feed) - return 0; - - for (i = 0; i < req->nb_streams; i++) { - AVCodecParameters *codec = req->streams[i]->codecpar; - - switch(rates[i]) { - case 0: - c->switch_feed_streams[i] = req->feed_streams[i]; - break; - case 1: - c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2); - break; - case 2: - /* Wants off or slow */ - c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4); -#ifdef WANTS_OFF - /* This doesn't work well when it turns off the only stream! */ - c->switch_feed_streams[i] = -2; - c->feed_streams[i] = -2; -#endif - break; - } - - if (c->switch_feed_streams[i] >= 0 && - c->switch_feed_streams[i] != c->feed_streams[i]) { - action_required = 1; - } - } - - return action_required; -} - -static void get_word(char *buf, int buf_size, const char **pp) -{ - const char *p; - char *q; - -#define SPACE_CHARS " \t\r\n" - - p = *pp; - p += strspn(p, SPACE_CHARS); - q = buf; - while (!av_isspace(*p) && *p != '\0') { - if ((q - buf) < buf_size - 1) - *q++ = *p; - p++; - } - if (buf_size > 0) - *q = '\0'; - *pp = p; -} - -static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream, - HTTPContext *c) -{ - FILE* f; - char line[1024]; - char cmd[1024]; - FFServerIPAddressACL *acl = NULL; - int line_num = 0; - const char *p; - - f = fopen(stream->dynamic_acl, "r"); - if (!f) { - perror(stream->dynamic_acl); - return NULL; - } - - acl = av_mallocz(sizeof(FFServerIPAddressACL)); - if (!acl) { - fclose(f); - return NULL; - } - - /* Build ACL */ - while (fgets(line, sizeof(line), f)) { - line_num++; - p = line; - while (av_isspace(*p)) - p++; - if (*p == '\0' || *p == '#') - continue; - ffserver_get_arg(cmd, sizeof(cmd), &p); - - if (!av_strcasecmp(cmd, "ACL")) - ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, - line_num); - } - fclose(f); - return acl; -} - - -static void free_acl_list(FFServerIPAddressACL *in_acl) -{ - FFServerIPAddressACL *pacl, *pacl2; - - pacl = in_acl; - while(pacl) { - pacl2 = pacl; - pacl = pacl->next; - av_freep(pacl2); - } -} - -static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c) -{ - enum FFServerIPAddressAction last_action = IP_DENY; - FFServerIPAddressACL *acl; - struct in_addr *src = &c->from_addr.sin_addr; - unsigned long src_addr = src->s_addr; - - for (acl = in_acl; acl; acl = acl->next) { - if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) - return (acl->action == IP_ALLOW) ? 1 : 0; - last_action = acl->action; - } - - /* Nothing matched, so return not the last action */ - return (last_action == IP_DENY) ? 1 : 0; -} - -static int validate_acl(FFServerStream *stream, HTTPContext *c) -{ - int ret = 0; - FFServerIPAddressACL *acl; - - /* if stream->acl is null validate_acl_list will return 1 */ - ret = validate_acl_list(stream->acl, c); - - if (stream->dynamic_acl[0]) { - acl = parse_dynamic_acl(stream, c); - ret = validate_acl_list(acl, c); - free_acl_list(acl); - } - - return ret; -} - -/** - * compute the real filename of a file by matching it without its - * extensions to all the stream's filenames - */ -static void compute_real_filename(char *filename, int max_size) -{ - char file1[1024]; - char file2[1024]; - char *p; - FFServerStream *stream; - - av_strlcpy(file1, filename, sizeof(file1)); - p = strrchr(file1, '.'); - if (p) - *p = '\0'; - for(stream = config.first_stream; stream; stream = stream->next) { - av_strlcpy(file2, stream->filename, sizeof(file2)); - p = strrchr(file2, '.'); - if (p) - *p = '\0'; - if (!strcmp(file1, file2)) { - av_strlcpy(filename, stream->filename, max_size); - break; - } - } -} - -enum RedirType { - REDIR_NONE, - REDIR_ASX, - REDIR_RAM, - REDIR_ASF, - REDIR_RTSP, - REDIR_SDP, -}; - -/* parse HTTP request and prepare header */ -static int http_parse_request(HTTPContext *c) -{ - const char *p; - char *p1; - enum RedirType redir_type; - char cmd[32]; - char info[1024], filename[1024]; - char url[1024], *q; - char protocol[32]; - char msg[1024]; - char *encoded_msg = NULL; - const char *mime_type; - FFServerStream *stream; - int i; - char ratebuf[32]; - const char *useragent = 0; - - p = c->buffer; - get_word(cmd, sizeof(cmd), &p); - av_strlcpy(c->method, cmd, sizeof(c->method)); - - if (!strcmp(cmd, "GET")) - c->post = 0; - else if (!strcmp(cmd, "POST")) - c->post = 1; - else - return -1; - - get_word(url, sizeof(url), &p); - av_strlcpy(c->url, url, sizeof(c->url)); - - get_word(protocol, sizeof(protocol), (const char **)&p); - if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1")) - return -1; - - av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); - - if (config.debug) - http_log("%s - - New connection: %s %s\n", - inet_ntoa(c->from_addr.sin_addr), cmd, url); - - /* find the filename and the optional info string in the request */ - p1 = strchr(url, '?'); - if (p1) { - av_strlcpy(info, p1, sizeof(info)); - *p1 = '\0'; - } else - info[0] = '\0'; - - av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1); - - for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { - if (av_strncasecmp(p, "User-Agent:", 11) == 0) { - useragent = p + 11; - if (*useragent && *useragent != '\n' && av_isspace(*useragent)) - useragent++; - break; - } - p = strchr(p, '\n'); - if (!p) - break; - - p++; - } - - redir_type = REDIR_NONE; - if (av_match_ext(filename, "asx")) { - redir_type = REDIR_ASX; - filename[strlen(filename)-1] = 'f'; - } else if (av_match_ext(filename, "asf") && - (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) { - /* if this isn't WMP or lookalike, return the redirector file */ - redir_type = REDIR_ASF; - } else if (av_match_ext(filename, "rpm,ram")) { - redir_type = REDIR_RAM; - strcpy(filename + strlen(filename)-2, "m"); - } else if (av_match_ext(filename, "rtsp")) { - redir_type = REDIR_RTSP; - compute_real_filename(filename, sizeof(filename) - 1); - } else if (av_match_ext(filename, "sdp")) { - redir_type = REDIR_SDP; - compute_real_filename(filename, sizeof(filename) - 1); - } - - /* "redirect" request to index.html */ - if (!strlen(filename)) - av_strlcpy(filename, "index.html", sizeof(filename) - 1); - - stream = config.first_stream; - while (stream) { - if (!strcmp(stream->filename, filename) && validate_acl(stream, c)) - break; - stream = stream->next; - } - if (!stream) { - snprintf(msg, sizeof(msg), "File '%s' not found", url); - http_log("File '%s' not found\n", url); - goto send_error; - } - - c->stream = stream; - memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams)); - memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams)); - - if (stream->stream_type == STREAM_TYPE_REDIRECT) { - c->http_error = 301; - q = c->buffer; - snprintf(q, c->buffer_size, - "HTTP/1.0 301 Moved\r\n" - "Location: %s\r\n" - "Content-type: text/html\r\n" - "\r\n" - "\n" - "Moved\r\n" - "You should be redirected.\r\n" - "\r\n", - stream->feed_filename, stream->feed_filename); - q += strlen(q); - /* prepare output buffer */ - c->buffer_ptr = c->buffer; - c->buffer_end = q; - c->state = HTTPSTATE_SEND_HEADER; - return 0; - } - - /* If this is WMP, get the rate information */ - if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) { - if (modify_current_stream(c, ratebuf)) { - for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) { - if (c->switch_feed_streams[i] >= 0) - c->switch_feed_streams[i] = -1; - } - } - } - - if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) - current_bandwidth += stream->bandwidth; - - /* If already streaming this feed, do not let another feeder start */ - if (stream->feed_opened) { - snprintf(msg, sizeof(msg), "This feed is already being received."); - http_log("Feed '%s' already being received\n", stream->feed_filename); - goto send_error; - } - - if (c->post == 0 && config.max_bandwidth < current_bandwidth) { - c->http_error = 503; - q = c->buffer; - snprintf(q, c->buffer_size, - "HTTP/1.0 503 Server too busy\r\n" - "Content-type: text/html\r\n" - "\r\n" - "\n" - "Too busy\r\n" - "

The server is too busy to serve your request at " - "this time.

\r\n" - "

The bandwidth being served (including your stream) " - "is %"PRIu64"kbit/s, and this exceeds the limit of " - "%"PRIu64"kbit/s.

\r\n" - "\r\n", - current_bandwidth, config.max_bandwidth); - q += strlen(q); - /* prepare output buffer */ - c->buffer_ptr = c->buffer; - c->buffer_end = q; - c->state = HTTPSTATE_SEND_HEADER; - return 0; - } - - if (redir_type != REDIR_NONE) { - const char *hostinfo = 0; - - for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { - if (av_strncasecmp(p, "Host:", 5) == 0) { - hostinfo = p + 5; - break; - } - p = strchr(p, '\n'); - if (!p) - break; - - p++; - } - - if (hostinfo) { - char *eoh; - char hostbuf[260]; - - while (av_isspace(*hostinfo)) - hostinfo++; - - eoh = strchr(hostinfo, '\n'); - if (eoh) { - if (eoh[-1] == '\r') - eoh--; - - if (eoh - hostinfo < sizeof(hostbuf) - 1) { - memcpy(hostbuf, hostinfo, eoh - hostinfo); - hostbuf[eoh - hostinfo] = 0; - - c->http_error = 200; - q = c->buffer; - switch(redir_type) { - case REDIR_ASX: - snprintf(q, c->buffer_size, - "HTTP/1.0 200 ASX Follows\r\n" - "Content-type: video/x-ms-asf\r\n" - "\r\n" - "\r\n" - //"\r\n" - "\r\n" - "\r\n", hostbuf, filename, info); - q += strlen(q); - break; - case REDIR_RAM: - snprintf(q, c->buffer_size, - "HTTP/1.0 200 RAM Follows\r\n" - "Content-type: audio/x-pn-realaudio\r\n" - "\r\n" - "# Autogenerated by ffserver\r\n" - "http://%s/%s%s\r\n", hostbuf, filename, info); - q += strlen(q); - break; - case REDIR_ASF: - snprintf(q, c->buffer_size, - "HTTP/1.0 200 ASF Redirect follows\r\n" - "Content-type: video/x-ms-asf\r\n" - "\r\n" - "[Reference]\r\n" - "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info); - q += strlen(q); - break; - case REDIR_RTSP: - { - char hostname[256], *p; - /* extract only hostname */ - av_strlcpy(hostname, hostbuf, sizeof(hostname)); - p = strrchr(hostname, ':'); - if (p) - *p = '\0'; - snprintf(q, c->buffer_size, - "HTTP/1.0 200 RTSP Redirect follows\r\n" - /* XXX: incorrect MIME type ? */ - "Content-type: application/x-rtsp\r\n" - "\r\n" - "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename); - q += strlen(q); - } - break; - case REDIR_SDP: - { - uint8_t *sdp_data; - int sdp_data_size; - socklen_t len; - struct sockaddr_in my_addr; - - snprintf(q, c->buffer_size, - "HTTP/1.0 200 OK\r\n" - "Content-type: application/sdp\r\n" - "\r\n"); - q += strlen(q); - - len = sizeof(my_addr); - - /* XXX: Should probably fail? */ - if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len)) - http_log("getsockname() failed\n"); - - /* XXX: should use a dynamic buffer */ - sdp_data_size = prepare_sdp_description(stream, - &sdp_data, - my_addr.sin_addr); - if (sdp_data_size > 0) { - memcpy(q, sdp_data, sdp_data_size); - q += sdp_data_size; - *q = '\0'; - av_freep(&sdp_data); - } - } - break; - default: - abort(); - break; - } - - /* prepare output buffer */ - c->buffer_ptr = c->buffer; - c->buffer_end = q; - c->state = HTTPSTATE_SEND_HEADER; - return 0; - } - } - } - - snprintf(msg, sizeof(msg), "ASX/RAM file not handled"); - goto send_error; - } - - stream->conns_served++; - - /* XXX: add there authenticate and IP match */ - - if (c->post) { - /* if post, it means a feed is being sent */ - if (!stream->is_feed) { - /* However it might be a status report from WMP! Let us log the - * data as it might come handy one day. */ - const char *logline = 0; - int client_id = 0; - - for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { - if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) { - logline = p; - break; - } - if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0) - client_id = strtol(p + 18, 0, 10); - p = strchr(p, '\n'); - if (!p) - break; - - p++; - } - - if (logline) { - char *eol = strchr(logline, '\n'); - - logline += 17; - - if (eol) { - if (eol[-1] == '\r') - eol--; - http_log("%.*s\n", (int) (eol - logline), logline); - c->suppress_log = 1; - } - } - -#ifdef DEBUG - http_log("\nGot request:\n%s\n", c->buffer); -#endif - - if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) { - HTTPContext *wmpc; - - /* Now we have to find the client_id */ - for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) { - if (wmpc->wmp_client_id == client_id) - break; - } - - if (wmpc && modify_current_stream(wmpc, ratebuf)) - wmpc->switch_pending = 1; - } - - snprintf(msg, sizeof(msg), "POST command not handled"); - c->stream = 0; - goto send_error; - } - if (http_start_receive_data(c) < 0) { - snprintf(msg, sizeof(msg), "could not open feed"); - goto send_error; - } - c->http_error = 0; - c->state = HTTPSTATE_RECEIVE_DATA; - return 0; - } - -#ifdef DEBUG - if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) - http_log("\nGot request:\n%s\n", c->buffer); -#endif - - if (c->stream->stream_type == STREAM_TYPE_STATUS) - goto send_status; - - /* open input stream */ - if (open_input_stream(c, info) < 0) { - snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url); - goto send_error; - } - - /* prepare HTTP header */ - c->buffer[0] = 0; - av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n"); - mime_type = c->stream->fmt->mime_type; - if (!mime_type) - mime_type = "application/x-octet-stream"; - av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n"); - - /* for asf, we need extra headers */ - if (!strcmp(c->stream->fmt->name,"asf_stream")) { - /* Need to allocate a client id */ - - c->wmp_client_id = av_lfg_get(&random_state); - - av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id); - } - av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type); - av_strlcatf(c->buffer, c->buffer_size, "\r\n"); - q = c->buffer + strlen(c->buffer); - - /* prepare output buffer */ - c->http_error = 0; - c->buffer_ptr = c->buffer; - c->buffer_end = q; - c->state = HTTPSTATE_SEND_HEADER; - return 0; - send_error: - c->http_error = 404; - q = c->buffer; - if (!htmlencode(msg, &encoded_msg)) { - http_log("Could not encode filename '%s' as HTML\n", msg); - } - snprintf(q, c->buffer_size, - "HTTP/1.0 404 Not Found\r\n" - "Content-type: text/html\r\n" - "\r\n" - "\n" - "\n" - "\n" - "\n" - "404 Not Found\n" - "\n" - "%s\n" - "\n", encoded_msg? encoded_msg : "File not found"); - q += strlen(q); - /* prepare output buffer */ - c->buffer_ptr = c->buffer; - c->buffer_end = q; - c->state = HTTPSTATE_SEND_HEADER; - av_freep(&encoded_msg); - return 0; - send_status: - compute_status(c); - /* horrible: we use this value to avoid - * going to the send data state */ - c->http_error = 200; - c->state = HTTPSTATE_SEND_HEADER; - return 0; -} - -static void fmt_bytecount(AVIOContext *pb, int64_t count) -{ - static const char suffix[] = " kMGTP"; - const char *s; - - for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++); - - avio_printf(pb, "%"PRId64"%c", count, *s); -} - -static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream) -{ - int i, stream_no; - const char *type = "unknown"; - char parameters[64]; - LayeredAVStream *st; - AVCodec *codec; - - stream_no = stream->nb_streams; - - avio_printf(pb, "
Stream" - "typekbit/scodec" - "Parameters\n"); - - for (i = 0; i < stream_no; i++) { - st = stream->streams[i]; - codec = avcodec_find_encoder(st->codecpar->codec_id); - - parameters[0] = 0; - - switch(st->codecpar->codec_type) { - case AVMEDIA_TYPE_AUDIO: - type = "audio"; - snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", - st->codecpar->channels, st->codecpar->sample_rate); - break; - case AVMEDIA_TYPE_VIDEO: - type = "video"; - snprintf(parameters, sizeof(parameters), - "%dx%d, q=%d-%d, fps=%d", st->codecpar->width, - st->codecpar->height, st->codec->qmin, st->codec->qmax, - st->time_base.den / st->time_base.num); - break; - default: - abort(); - } - - avio_printf(pb, "
%d%s%"PRId64 - "%s%s\n", - i, type, st->codecpar->bit_rate/1000, - codec ? codec->name : "", parameters); - } - - avio_printf(pb, "
\n"); -} - -static void clean_html(char *clean, int clean_len, char *dirty) -{ - int i, o; - - for (o = i = 0; o+10 < clean_len && dirty[i];) { - int len = strspn(dirty+i, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$-_.+!*(),?/ :;%"); - if (len) { - if (o + len >= clean_len) - break; - memcpy(clean + o, dirty + i, len); - i += len; - o += len; - } else { - int c = dirty[i++]; - switch (c) { - case '&': av_strlcat(clean+o, "&" , clean_len - o); break; - case '<': av_strlcat(clean+o, "<" , clean_len - o); break; - case '>': av_strlcat(clean+o, ">" , clean_len - o); break; - case '\'': av_strlcat(clean+o, "'" , clean_len - o); break; - case '\"': av_strlcat(clean+o, """ , clean_len - o); break; - default: av_strlcat(clean+o, "☹", clean_len - o); break; - } - o += strlen(clean+o); - } - } - clean[o] = 0; -} - -static void compute_status(HTTPContext *c) -{ - HTTPContext *c1; - FFServerStream *stream; - char *p; - time_t ti; - int i, len; - AVIOContext *pb; - - if (avio_open_dyn_buf(&pb) < 0) { - /* XXX: return an error ? */ - c->buffer_ptr = c->buffer; - c->buffer_end = c->buffer; - return; - } - - avio_printf(pb, "HTTP/1.0 200 OK\r\n"); - avio_printf(pb, "Content-type: text/html\r\n"); - avio_printf(pb, "Pragma: no-cache\r\n"); - avio_printf(pb, "\r\n"); - - avio_printf(pb, "\n"); - avio_printf(pb, "%s Status\n", program_name); - if (c->stream->feed_filename[0]) - avio_printf(pb, "\n", - c->stream->feed_filename); - avio_printf(pb, "\n"); - avio_printf(pb, "

%s Status

\n", program_name); - /* format status */ - avio_printf(pb, "

Available Streams

\n"); - avio_printf(pb, "\n"); - avio_printf(pb, "
PathServed
Conns

bytes
FormatBit rate
kbit/s
Video
kbit/s

Codec
Audio
kbit/s

Codec
Feed\n"); - stream = config.first_stream; - while (stream) { - char sfilename[1024]; - char *eosf; - - if (stream->feed == stream) { - stream = stream->next; - continue; - } - - av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10); - eosf = sfilename + strlen(sfilename); - if (eosf - sfilename >= 4) { - if (strcmp(eosf - 4, ".asf") == 0) - strcpy(eosf - 4, ".asx"); - else if (strcmp(eosf - 3, ".rm") == 0) - strcpy(eosf - 3, ".ram"); - else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) { - /* generate a sample RTSP director if - * unicast. Generate an SDP redirector if - * multicast */ - eosf = strrchr(sfilename, '.'); - if (!eosf) - eosf = sfilename + strlen(sfilename); - if (stream->is_multicast) - strcpy(eosf, ".sdp"); - else - strcpy(eosf, ".rtsp"); - } - } - - avio_printf(pb, "
%s ", - sfilename, stream->filename); - avio_printf(pb, " %d ", - stream->conns_served); - // TODO: Investigate if we can make http bitexact so it always produces the same count of bytes - if (!config.bitexact) - fmt_bytecount(pb, stream->bytes_served); - - switch(stream->stream_type) { - case STREAM_TYPE_LIVE: { - int audio_bit_rate = 0; - int video_bit_rate = 0; - const char *audio_codec_name = ""; - const char *video_codec_name = ""; - const char *audio_codec_name_extra = ""; - const char *video_codec_name_extra = ""; - - for(i=0;inb_streams;i++) { - LayeredAVStream *st = stream->streams[i]; - AVCodec *codec = avcodec_find_encoder(st->codecpar->codec_id); - - switch(st->codecpar->codec_type) { - case AVMEDIA_TYPE_AUDIO: - audio_bit_rate += st->codecpar->bit_rate; - if (codec) { - if (*audio_codec_name) - audio_codec_name_extra = "..."; - audio_codec_name = codec->name; - } - break; - case AVMEDIA_TYPE_VIDEO: - video_bit_rate += st->codecpar->bit_rate; - if (codec) { - if (*video_codec_name) - video_codec_name_extra = "..."; - video_codec_name = codec->name; - } - break; - case AVMEDIA_TYPE_DATA: - video_bit_rate += st->codecpar->bit_rate; - break; - default: - abort(); - } - } - - avio_printf(pb, " %s %d %d %s %s " - "%d %s %s", - stream->fmt->name, stream->bandwidth, - video_bit_rate / 1000, video_codec_name, - video_codec_name_extra, audio_bit_rate / 1000, - audio_codec_name, audio_codec_name_extra); - - if (stream->feed) - avio_printf(pb, "%s", stream->feed->filename); - else - avio_printf(pb, "%s", stream->feed_filename); - avio_printf(pb, "\n"); - } - break; - default: - avio_printf(pb, " - - " - " - - \n"); - break; - } - stream = stream->next; - } - avio_printf(pb, "
\n"); - - stream = config.first_stream; - while (stream) { - - if (stream->feed != stream) { - stream = stream->next; - continue; - } - - avio_printf(pb, "

Feed %s

", stream->filename); - if (stream->pid) { - avio_printf(pb, "Running as pid %"PRId64".\n", (int64_t) stream->pid); - -#if defined(linux) - { - FILE *pid_stat; - char ps_cmd[64]; - - /* This is somewhat linux specific I guess */ - snprintf(ps_cmd, sizeof(ps_cmd), - "ps -o \"%%cpu,cputime\" --no-headers %"PRId64"", - (int64_t) stream->pid); - - pid_stat = popen(ps_cmd, "r"); - if (pid_stat) { - char cpuperc[10]; - char cpuused[64]; - - if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) { - avio_printf(pb, "Currently using %s%% of the cpu. " - "Total time used %s.\n", - cpuperc, cpuused); - } - fclose(pid_stat); - } - } -#endif - - avio_printf(pb, "

"); - } - - print_stream_params(pb, stream); - stream = stream->next; - } - - /* connection status */ - avio_printf(pb, "

Connection Status

\n"); - - avio_printf(pb, "Number of connections: %d / %d
\n", - nb_connections, config.nb_max_connections); - - avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k
\n", - current_bandwidth, config.max_bandwidth); - - avio_printf(pb, "\n"); - avio_printf(pb, "
#FileIPURLProtoStateTarget " - "bit/sActual bit/sBytes transferred\n"); - c1 = first_http_ctx; - i = 0; - while (c1) { - int bitrate; - int j; - - bitrate = 0; - if (c1->stream) { - for (j = 0; j < c1->stream->nb_streams; j++) { - if (!c1->stream->feed) - bitrate += c1->stream->streams[j]->codecpar->bit_rate; - else if (c1->feed_streams[j] >= 0) - bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codecpar->bit_rate; - } - } - - i++; - p = inet_ntoa(c1->from_addr.sin_addr); - clean_html(c1->clean_url, sizeof(c1->clean_url), c1->url); - avio_printf(pb, "
%d%s%s%s%s%s%s" - "", - i, c1->stream ? c1->stream->filename : "", - c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", - p, - c1->clean_url, - c1->protocol, http_state[c1->state]); - fmt_bytecount(pb, bitrate); - avio_printf(pb, ""); - fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8); - avio_printf(pb, ""); - fmt_bytecount(pb, c1->data_count); - avio_printf(pb, "\n"); - c1 = c1->next; - } - avio_printf(pb, "
\n"); - - if (!config.bitexact) { - /* date */ - ti = time(NULL); - p = ctime(&ti); - avio_printf(pb, "
Generated at %s", p); - } - avio_printf(pb, "\n\n"); - - len = avio_close_dyn_buf(pb, &c->pb_buffer); - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; -} - -static int open_input_stream(HTTPContext *c, const char *info) -{ - char buf[128]; - char input_filename[1024]; - AVFormatContext *s = NULL; - int buf_size, i, ret; - int64_t stream_pos; - - /* find file name */ - if (c->stream->feed) { - strcpy(input_filename, c->stream->feed->feed_filename); - buf_size = FFM_PACKET_SIZE; - /* compute position (absolute time) */ - if (av_find_info_tag(buf, sizeof(buf), "date", info)) { - if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) { - http_log("Invalid date specification '%s' for stream\n", buf); - return ret; - } - } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) { - int prebuffer = strtol(buf, 0, 10); - stream_pos = av_gettime() - prebuffer * (int64_t)1000000; - } else - stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000; - } else { - strcpy(input_filename, c->stream->feed_filename); - buf_size = 0; - /* compute position (relative time) */ - if (av_find_info_tag(buf, sizeof(buf), "date", info)) { - if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) { - http_log("Invalid date specification '%s' for stream\n", buf); - return ret; - } - } else - stream_pos = 0; - } - if (!input_filename[0]) { - http_log("No filename was specified for stream\n"); - return AVERROR(EINVAL); - } - - /* open stream */ - ret = avformat_open_input(&s, input_filename, c->stream->ifmt, - &c->stream->in_opts); - if (ret < 0) { - http_log("Could not open input '%s': %s\n", - input_filename, av_err2str(ret)); - return ret; - } - - /* set buffer size */ - if (buf_size > 0) { - ret = ffio_set_buf_size(s->pb, buf_size); - if (ret < 0) { - http_log("Failed to set buffer size\n"); - return ret; - } - } - - s->flags |= AVFMT_FLAG_GENPTS; - c->fmt_in = s; - if (strcmp(s->iformat->name, "ffm") && - (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) { - http_log("Could not find stream info for input '%s'\n", input_filename); - avformat_close_input(&s); - return ret; - } - - /* choose stream as clock source (we favor the video stream if - * present) for packet sending */ - c->pts_stream_index = 0; - for(i=0;istream->nb_streams;i++) { - if (c->pts_stream_index == 0 && - c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - c->pts_stream_index = i; - } - } - - if (c->fmt_in->iformat->read_seek) - av_seek_frame(c->fmt_in, -1, stream_pos, 0); - /* set the start time (needed for maxtime and RTP packet timing) */ - c->start_time = cur_time; - c->first_pts = AV_NOPTS_VALUE; - return 0; -} - -/* return the server clock (in us) */ -static int64_t get_server_clock(HTTPContext *c) -{ - /* compute current pts value from system time */ - return (cur_time - c->start_time) * 1000; -} - -/* return the estimated time (in us) at which the current packet must be sent */ -static int64_t get_packet_send_clock(HTTPContext *c) -{ - int bytes_left, bytes_sent, frame_bytes; - - frame_bytes = c->cur_frame_bytes; - if (frame_bytes <= 0) - return c->cur_pts; - - bytes_left = c->buffer_end - c->buffer_ptr; - bytes_sent = frame_bytes - bytes_left; - return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes; -} - - -static int http_prepare_data(HTTPContext *c) -{ - int i, len, ret; - AVFormatContext *ctx; - - av_freep(&c->pb_buffer); - switch(c->state) { - case HTTPSTATE_SEND_DATA_HEADER: - ctx = avformat_alloc_context(); - if (!ctx) - return AVERROR(ENOMEM); - c->pfmt_ctx = ctx; - av_dict_copy(&(c->pfmt_ctx->metadata), c->stream->metadata, 0); - - for(i=0;istream->nb_streams;i++) { - LayeredAVStream *src; - AVStream *st = avformat_new_stream(c->pfmt_ctx, NULL); - if (!st) - return AVERROR(ENOMEM); - - /* if file or feed, then just take streams from FFServerStream - * struct */ - if (!c->stream->feed || - c->stream->feed == c->stream) - src = c->stream->streams[i]; - else - src = c->stream->feed->streams[c->stream->feed_streams[i]]; - - unlayer_stream(c->pfmt_ctx->streams[i], src); //TODO we no longer copy st->internal, does this matter? - av_assert0(!c->pfmt_ctx->streams[i]->priv_data); - - if (src->codec->flags & AV_CODEC_FLAG_BITEXACT) - c->pfmt_ctx->flags |= AVFMT_FLAG_BITEXACT; - } - /* set output format parameters */ - c->pfmt_ctx->oformat = c->stream->fmt; - av_assert0(c->pfmt_ctx->nb_streams == c->stream->nb_streams); - - c->got_key_frame = 0; - - /* prepare header and save header data in a stream */ - if (avio_open_dyn_buf(&c->pfmt_ctx->pb) < 0) { - /* XXX: potential leak */ - return -1; - } - c->pfmt_ctx->pb->seekable = 0; - - /* - * HACK to avoid MPEG-PS muxer to spit many underflow errors - * Default value from FFmpeg - * Try to set it using configuration option - */ - c->pfmt_ctx->max_delay = (int)(0.7*AV_TIME_BASE); - - if ((ret = avformat_write_header(c->pfmt_ctx, NULL)) < 0) { - http_log("Error writing output header for stream '%s': %s\n", - c->stream->filename, av_err2str(ret)); - return ret; - } - av_dict_free(&c->pfmt_ctx->metadata); - - len = avio_close_dyn_buf(c->pfmt_ctx->pb, &c->pb_buffer); - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - - c->state = HTTPSTATE_SEND_DATA; - c->last_packet_sent = 0; - break; - case HTTPSTATE_SEND_DATA: - /* find a new packet */ - /* read a packet from the input stream */ - if (c->stream->feed) - ffm_set_write_index(c->fmt_in, - c->stream->feed->feed_write_index, - c->stream->feed->feed_size); - - if (c->stream->max_time && - c->stream->max_time + c->start_time - cur_time < 0) - /* We have timed out */ - c->state = HTTPSTATE_SEND_DATA_TRAILER; - else { - AVPacket pkt; - redo: - ret = av_read_frame(c->fmt_in, &pkt); - if (ret < 0) { - if (c->stream->feed) { - /* if coming from feed, it means we reached the end of the - * ffm file, so must wait for more data */ - c->state = HTTPSTATE_WAIT_FEED; - return 1; /* state changed */ - } - if (ret == AVERROR(EAGAIN)) { - /* input not ready, come back later */ - return 0; - } - if (c->stream->loop) { - avformat_close_input(&c->fmt_in); - if (open_input_stream(c, "") < 0) - goto no_loop; - goto redo; - } else { - no_loop: - /* must send trailer now because EOF or error */ - c->state = HTTPSTATE_SEND_DATA_TRAILER; - } - } else { - int source_index = pkt.stream_index; - /* update first pts if needed */ - if (c->first_pts == AV_NOPTS_VALUE && pkt.dts != AV_NOPTS_VALUE) { - c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q); - c->start_time = cur_time; - } - /* send it to the appropriate stream */ - if (c->stream->feed) { - /* if coming from a feed, select the right stream */ - if (c->switch_pending) { - c->switch_pending = 0; - for(i=0;istream->nb_streams;i++) { - if (c->switch_feed_streams[i] == pkt.stream_index) - if (pkt.flags & AV_PKT_FLAG_KEY) - c->switch_feed_streams[i] = -1; - if (c->switch_feed_streams[i] >= 0) - c->switch_pending = 1; - } - } - for(i=0;istream->nb_streams;i++) { - if (c->stream->feed_streams[i] == pkt.stream_index) { - AVStream *st = c->fmt_in->streams[source_index]; - pkt.stream_index = i; - if (pkt.flags & AV_PKT_FLAG_KEY && - (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || - c->stream->nb_streams == 1)) - c->got_key_frame = 1; - if (!c->stream->send_on_key || c->got_key_frame) - goto send_it; - } - } - } else { - AVStream *ist, *ost; - send_it: - ist = c->fmt_in->streams[source_index]; - /* specific handling for RTP: we use several - * output streams (one for each RTP connection). - * XXX: need more abstract handling */ - if (c->is_packetized) { - /* compute send time and duration */ - if (pkt.dts != AV_NOPTS_VALUE) { - c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q); - c->cur_pts -= c->first_pts; - } - c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q); - /* find RTP context */ - c->packet_stream_index = pkt.stream_index; - ctx = c->rtp_ctx[c->packet_stream_index]; - if(!ctx) { - av_packet_unref(&pkt); - break; - } - /* only one stream per RTP connection */ - pkt.stream_index = 0; - } else { - ctx = c->pfmt_ctx; - /* Fudge here */ - } - - if (c->is_packetized) { - int max_packet_size; - if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) - max_packet_size = RTSP_TCP_MAX_PACKET_SIZE; - else - max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size; - ret = ffio_open_dyn_packet_buf(&ctx->pb, - max_packet_size); - } else - ret = avio_open_dyn_buf(&ctx->pb); - - if (ret < 0) { - /* XXX: potential leak */ - return -1; - } - ost = ctx->streams[pkt.stream_index]; - - ctx->pb->seekable = 0; - if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, ist->time_base, - ost->time_base); - if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, ist->time_base, - ost->time_base); - pkt.duration = av_rescale_q(pkt.duration, ist->time_base, - ost->time_base); - if ((ret = av_write_frame(ctx, &pkt)) < 0) { - http_log("Error writing frame to output for stream '%s': %s\n", - c->stream->filename, av_err2str(ret)); - c->state = HTTPSTATE_SEND_DATA_TRAILER; - } - - av_freep(&c->pb_buffer); - len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer); - ctx->pb = NULL; - c->cur_frame_bytes = len; - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - - if (len == 0) { - av_packet_unref(&pkt); - goto redo; - } - } - av_packet_unref(&pkt); - } - } - break; - default: - case HTTPSTATE_SEND_DATA_TRAILER: - /* last packet test ? */ - if (c->last_packet_sent || c->is_packetized) - return -1; - ctx = c->pfmt_ctx; - /* prepare header */ - if (avio_open_dyn_buf(&ctx->pb) < 0) { - /* XXX: potential leak */ - return -1; - } - c->pfmt_ctx->pb->seekable = 0; - av_write_trailer(ctx); - len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer); - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - - c->last_packet_sent = 1; - break; - } - return 0; -} - -/* should convert the format at the same time */ -/* send data starting at c->buffer_ptr to the output connection - * (either UDP or TCP) - */ -static int http_send_data(HTTPContext *c) -{ - int len, ret; - - for(;;) { - if (c->buffer_ptr >= c->buffer_end) { - ret = http_prepare_data(c); - if (ret < 0) - return -1; - else if (ret) - /* state change requested */ - break; - } else { - if (c->is_packetized) { - /* RTP data output */ - len = c->buffer_end - c->buffer_ptr; - if (len < 4) { - /* fail safe - should never happen */ - fail1: - c->buffer_ptr = c->buffer_end; - return 0; - } - len = (c->buffer_ptr[0] << 24) | - (c->buffer_ptr[1] << 16) | - (c->buffer_ptr[2] << 8) | - (c->buffer_ptr[3]); - if (len > (c->buffer_end - c->buffer_ptr)) - goto fail1; - if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) { - /* nothing to send yet: we can wait */ - return 0; - } - - c->data_count += len; - update_datarate(&c->datarate, c->data_count); - if (c->stream) - c->stream->bytes_served += len; - - if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) { - /* RTP packets are sent inside the RTSP TCP connection */ - AVIOContext *pb; - int interleaved_index, size; - uint8_t header[4]; - HTTPContext *rtsp_c; - - rtsp_c = c->rtsp_c; - /* if no RTSP connection left, error */ - if (!rtsp_c) - return -1; - /* if already sending something, then wait. */ - if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) - break; - if (avio_open_dyn_buf(&pb) < 0) - goto fail1; - interleaved_index = c->packet_stream_index * 2; - /* RTCP packets are sent at odd indexes */ - if (c->buffer_ptr[1] == 200) - interleaved_index++; - /* write RTSP TCP header */ - header[0] = '$'; - header[1] = interleaved_index; - header[2] = len >> 8; - header[3] = len; - avio_write(pb, header, 4); - /* write RTP packet data */ - c->buffer_ptr += 4; - avio_write(pb, c->buffer_ptr, len); - size = avio_close_dyn_buf(pb, &c->packet_buffer); - /* prepare asynchronous TCP sending */ - rtsp_c->packet_buffer_ptr = c->packet_buffer; - rtsp_c->packet_buffer_end = c->packet_buffer + size; - c->buffer_ptr += len; - - /* send everything we can NOW */ - len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr, - rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0); - if (len > 0) - rtsp_c->packet_buffer_ptr += len; - if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) { - /* if we could not send all the data, we will - * send it later, so a new state is needed to - * "lock" the RTSP TCP connection */ - rtsp_c->state = RTSPSTATE_SEND_PACKET; - break; - } else - /* all data has been sent */ - av_freep(&c->packet_buffer); - } else { - /* send RTP packet directly in UDP */ - c->buffer_ptr += 4; - ffurl_write(c->rtp_handles[c->packet_stream_index], - c->buffer_ptr, len); - c->buffer_ptr += len; - /* here we continue as we can send several packets - * per 10 ms slot */ - } - } else { - /* TCP data output */ - len = send(c->fd, c->buffer_ptr, - c->buffer_end - c->buffer_ptr, 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - /* error : close connection */ - return -1; - else - return 0; - } - c->buffer_ptr += len; - - c->data_count += len; - update_datarate(&c->datarate, c->data_count); - if (c->stream) - c->stream->bytes_served += len; - break; - } - } - } /* for(;;) */ - return 0; -} - -static int http_start_receive_data(HTTPContext *c) -{ - int fd; - int ret; - int64_t ret64; - - if (c->stream->feed_opened) { - http_log("Stream feed '%s' was not opened\n", - c->stream->feed_filename); - return AVERROR(EINVAL); - } - - /* Don't permit writing to this one */ - if (c->stream->readonly) { - http_log("Cannot write to read-only file '%s'\n", - c->stream->feed_filename); - return AVERROR(EINVAL); - } - - /* open feed */ - fd = open(c->stream->feed_filename, O_RDWR); - if (fd < 0) { - ret = AVERROR(errno); - http_log("Could not open feed file '%s': %s\n", - c->stream->feed_filename, strerror(errno)); - return ret; - } - c->feed_fd = fd; - - if (c->stream->truncate) { - /* truncate feed file */ - ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE); - http_log("Truncating feed file '%s'\n", c->stream->feed_filename); - if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) { - ret = AVERROR(errno); - http_log("Error truncating feed file '%s': %s\n", - c->stream->feed_filename, strerror(errno)); - return ret; - } - } else { - ret64 = ffm_read_write_index(fd); - if (ret64 < 0) { - http_log("Error reading write index from feed file '%s': %s\n", - c->stream->feed_filename, strerror(errno)); - return ret64; - } - c->stream->feed_write_index = ret64; - } - - c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), - FFM_PACKET_SIZE); - c->stream->feed_size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - - /* init buffer input */ - c->buffer_ptr = c->buffer; - c->buffer_end = c->buffer + FFM_PACKET_SIZE; - c->stream->feed_opened = 1; - c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked"); - return 0; -} - -static int http_receive_data(HTTPContext *c) -{ - HTTPContext *c1; - int len, loop_run = 0; - - while (c->chunked_encoding && !c->chunk_size && - c->buffer_end > c->buffer_ptr) { - /* read chunk header, if present */ - len = recv(c->fd, c->buffer_ptr, 1, 0); - - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - /* error : close connection */ - goto fail; - return 0; - } else if (len == 0) { - /* end of connection : close it */ - goto fail; - } else if (c->buffer_ptr - c->buffer >= 2 && - !memcmp(c->buffer_ptr - 1, "\r\n", 2)) { - c->chunk_size = strtol(c->buffer, 0, 16); - if (c->chunk_size <= 0) { // end of stream or invalid chunk size - c->chunk_size = 0; - goto fail; - } - c->buffer_ptr = c->buffer; - break; - } else if (++loop_run > 10) - /* no chunk header, abort */ - goto fail; - else - c->buffer_ptr++; - } - - if (c->buffer_end > c->buffer_ptr) { - len = recv(c->fd, c->buffer_ptr, - FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - /* error : close connection */ - goto fail; - } else if (len == 0) - /* end of connection : close it */ - goto fail; - else { - av_assert0(len <= c->chunk_size); - c->chunk_size -= len; - c->buffer_ptr += len; - c->data_count += len; - update_datarate(&c->datarate, c->data_count); - } - } - - if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) { - if (c->buffer[0] != 'f' || - c->buffer[1] != 'm') { - http_log("Feed stream has become desynchronized -- disconnecting\n"); - goto fail; - } - } - - if (c->buffer_ptr >= c->buffer_end) { - FFServerStream *feed = c->stream; - /* a packet has been received : write it in the store, except - * if header */ - if (c->data_count > FFM_PACKET_SIZE) { - /* XXX: use llseek or url_seek - * XXX: Should probably fail? */ - if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1) - http_log("Seek to %"PRId64" failed\n", feed->feed_write_index); - - if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) { - http_log("Error writing to feed file: %s\n", strerror(errno)); - goto fail; - } - - feed->feed_write_index += FFM_PACKET_SIZE; - /* update file size */ - if (feed->feed_write_index > c->stream->feed_size) - feed->feed_size = feed->feed_write_index; - - /* handle wrap around if max file size reached */ - if (c->stream->feed_max_size && - feed->feed_write_index >= c->stream->feed_max_size) - feed->feed_write_index = FFM_PACKET_SIZE; - - /* write index */ - if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) { - http_log("Error writing index to feed file: %s\n", - strerror(errno)); - goto fail; - } - - /* wake up any waiting connections */ - for(c1 = first_http_ctx; c1; c1 = c1->next) { - if (c1->state == HTTPSTATE_WAIT_FEED && - c1->stream->feed == c->stream->feed) - c1->state = HTTPSTATE_SEND_DATA; - } - } else { - /* We have a header in our hands that contains useful data */ - AVFormatContext *s = avformat_alloc_context(); - AVIOContext *pb; - AVInputFormat *fmt_in; - int i; - - if (!s) - goto fail; - - /* use feed output format name to find corresponding input format */ - fmt_in = av_find_input_format(feed->fmt->name); - if (!fmt_in) - goto fail; - - pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer, - 0, NULL, NULL, NULL, NULL); - if (!pb) - goto fail; - - pb->seekable = 0; - - s->pb = pb; - if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) { - av_freep(&pb); - goto fail; - } - - /* Now we have the actual streams */ - if (s->nb_streams != feed->nb_streams) { - avformat_close_input(&s); - av_freep(&pb); - http_log("Feed '%s' stream number does not match registered feed\n", - c->stream->feed_filename); - goto fail; - } - - for (i = 0; i < s->nb_streams; i++) { - LayeredAVStream *fst = feed->streams[i]; - AVStream *st = s->streams[i]; - avcodec_parameters_to_context(fst->codec, st->codecpar); - avcodec_parameters_from_context(fst->codecpar, fst->codec); - } - - avformat_close_input(&s); - av_freep(&pb); - } - c->buffer_ptr = c->buffer; - } - - return 0; - fail: - c->stream->feed_opened = 0; - close(c->feed_fd); - /* wake up any waiting connections to stop waiting for feed */ - for(c1 = first_http_ctx; c1; c1 = c1->next) { - if (c1->state == HTTPSTATE_WAIT_FEED && - c1->stream->feed == c->stream->feed) - c1->state = HTTPSTATE_SEND_DATA_TRAILER; - } - return -1; -} - -/********************************************************************/ -/* RTSP handling */ - -static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number) -{ - const char *str; - time_t ti; - struct tm *tm; - char buf2[32]; - - str = RTSP_STATUS_CODE2STRING(error_number); - if (!str) - str = "Unknown Error"; - - avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str); - avio_printf(c->pb, "CSeq: %d\r\n", c->seq); - - /* output GMT time */ - ti = time(NULL); - tm = gmtime(&ti); - strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm); - avio_printf(c->pb, "Date: %s GMT\r\n", buf2); -} - -static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number) -{ - rtsp_reply_header(c, error_number); - avio_printf(c->pb, "\r\n"); -} - -static int rtsp_parse_request(HTTPContext *c) -{ - const char *p, *p1, *p2; - char cmd[32]; - char url[1024]; - char protocol[32]; - char line[1024]; - int len; - RTSPMessageHeader header1 = { 0 }, *header = &header1; - - c->buffer_ptr[0] = '\0'; - p = c->buffer; - - get_word(cmd, sizeof(cmd), &p); - get_word(url, sizeof(url), &p); - get_word(protocol, sizeof(protocol), &p); - - av_strlcpy(c->method, cmd, sizeof(c->method)); - av_strlcpy(c->url, url, sizeof(c->url)); - av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); - - if (avio_open_dyn_buf(&c->pb) < 0) { - /* XXX: cannot do more */ - c->pb = NULL; /* safety */ - return -1; - } - - /* check version name */ - if (strcmp(protocol, "RTSP/1.0")) { - rtsp_reply_error(c, RTSP_STATUS_VERSION); - goto the_end; - } - - /* parse each header line */ - /* skip to next line */ - while (*p != '\n' && *p != '\0') - p++; - if (*p == '\n') - p++; - while (*p != '\0') { - p1 = memchr(p, '\n', (char *)c->buffer_ptr - p); - if (!p1) - break; - p2 = p1; - if (p2 > p && p2[-1] == '\r') - p2--; - /* skip empty line */ - if (p2 == p) - break; - len = p2 - p; - if (len > sizeof(line) - 1) - len = sizeof(line) - 1; - memcpy(line, p, len); - line[len] = '\0'; - ff_rtsp_parse_line(NULL, header, line, NULL, NULL); - p = p1 + 1; - } - - /* handle sequence number */ - c->seq = header->seq; - - if (!strcmp(cmd, "DESCRIBE")) - rtsp_cmd_describe(c, url); - else if (!strcmp(cmd, "OPTIONS")) - rtsp_cmd_options(c, url); - else if (!strcmp(cmd, "SETUP")) - rtsp_cmd_setup(c, url, header); - else if (!strcmp(cmd, "PLAY")) - rtsp_cmd_play(c, url, header); - else if (!strcmp(cmd, "PAUSE")) - rtsp_cmd_interrupt(c, url, header, 1); - else if (!strcmp(cmd, "TEARDOWN")) - rtsp_cmd_interrupt(c, url, header, 0); - else - rtsp_reply_error(c, RTSP_STATUS_METHOD); - - the_end: - len = avio_close_dyn_buf(c->pb, &c->pb_buffer); - c->pb = NULL; /* safety */ - if (len < 0) - /* XXX: cannot do more */ - return -1; - - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - c->state = RTSPSTATE_SEND_REPLY; - return 0; -} - -static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer, - struct in_addr my_ip) -{ - AVFormatContext *avc; - AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); - AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0); - int i; - - *pbuffer = NULL; - - avc = avformat_alloc_context(); - if (!avc || !rtp_format) - return -1; - - avc->oformat = rtp_format; - av_dict_set(&avc->metadata, "title", - entry ? entry->value : "No Title", 0); - if (stream->is_multicast) { - snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d", - inet_ntoa(stream->multicast_ip), - stream->multicast_port, stream->multicast_ttl); - } else - snprintf(avc->filename, 1024, "rtp://0.0.0.0"); - - for(i = 0; i < stream->nb_streams; i++) { - AVStream *st = avformat_new_stream(avc, NULL); - if (!st) - goto sdp_done; - avcodec_parameters_from_context(stream->streams[i]->codecpar, stream->streams[i]->codec); - unlayer_stream(st, stream->streams[i]); - } -#define PBUFFER_SIZE 2048 - *pbuffer = av_mallocz(PBUFFER_SIZE); - if (!*pbuffer) - goto sdp_done; - av_sdp_create(&avc, 1, *pbuffer, PBUFFER_SIZE); - - sdp_done: - av_freep(&avc->streams); - av_dict_free(&avc->metadata); - av_free(avc); - - return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM); -} - -static void rtsp_cmd_options(HTTPContext *c, const char *url) -{ - /* rtsp_reply_header(c, RTSP_STATUS_OK); */ - avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK"); - avio_printf(c->pb, "CSeq: %d\r\n", c->seq); - avio_printf(c->pb, "Public: %s\r\n", - "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE"); - avio_printf(c->pb, "\r\n"); -} - -static void rtsp_cmd_describe(HTTPContext *c, const char *url) -{ - FFServerStream *stream; - char path1[1024]; - const char *path; - uint8_t *content; - int content_length; - socklen_t len; - struct sockaddr_in my_addr; - - /* find which URL is asked */ - av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); - path = path1; - if (*path == '/') - path++; - - for(stream = config.first_stream; stream; stream = stream->next) { - if (!stream->is_feed && - stream->fmt && !strcmp(stream->fmt->name, "rtp") && - !strcmp(path, stream->filename)) { - goto found; - } - } - /* no stream found */ - rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND); - return; - - found: - /* prepare the media description in SDP format */ - - /* get the host IP */ - len = sizeof(my_addr); - getsockname(c->fd, (struct sockaddr *)&my_addr, &len); - content_length = prepare_sdp_description(stream, &content, - my_addr.sin_addr); - if (content_length < 0) { - rtsp_reply_error(c, RTSP_STATUS_INTERNAL); - return; - } - rtsp_reply_header(c, RTSP_STATUS_OK); - avio_printf(c->pb, "Content-Base: %s/\r\n", url); - avio_printf(c->pb, "Content-Type: application/sdp\r\n"); - avio_printf(c->pb, "Content-Length: %d\r\n", content_length); - avio_printf(c->pb, "\r\n"); - avio_write(c->pb, content, content_length); - av_free(content); -} - -static HTTPContext *find_rtp_session(const char *session_id) -{ - HTTPContext *c; - - if (session_id[0] == '\0') - return NULL; - - for(c = first_http_ctx; c; c = c->next) { - if (!strcmp(c->session_id, session_id)) - return c; - } - return NULL; -} - -static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport) -{ - RTSPTransportField *th; - int i; - - for(i=0;inb_transports;i++) { - th = &h->transports[i]; - if (th->lower_transport == lower_transport) - return th; - } - return NULL; -} - -static void rtsp_cmd_setup(HTTPContext *c, const char *url, - RTSPMessageHeader *h) -{ - FFServerStream *stream; - int stream_index, rtp_port, rtcp_port; - char buf[1024]; - char path1[1024]; - const char *path; - HTTPContext *rtp_c; - RTSPTransportField *th; - struct sockaddr_in dest_addr; - RTSPActionServerSetup setup; - - /* find which URL is asked */ - av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); - path = path1; - if (*path == '/') - path++; - - /* now check each stream */ - for(stream = config.first_stream; stream; stream = stream->next) { - if (stream->is_feed || !stream->fmt || - strcmp(stream->fmt->name, "rtp")) { - continue; - } - /* accept aggregate filenames only if single stream */ - if (!strcmp(path, stream->filename)) { - if (stream->nb_streams != 1) { - rtsp_reply_error(c, RTSP_STATUS_AGGREGATE); - return; - } - stream_index = 0; - goto found; - } - - for(stream_index = 0; stream_index < stream->nb_streams; - stream_index++) { - snprintf(buf, sizeof(buf), "%s/streamid=%d", - stream->filename, stream_index); - if (!strcmp(path, buf)) - goto found; - } - } - /* no stream found */ - rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */ - return; - found: - - /* generate session id if needed */ - if (h->session_id[0] == '\0') { - unsigned random0 = av_lfg_get(&random_state); - unsigned random1 = av_lfg_get(&random_state); - snprintf(h->session_id, sizeof(h->session_id), "%08x%08x", - random0, random1); - } - - /* find RTP session, and create it if none found */ - rtp_c = find_rtp_session(h->session_id); - if (!rtp_c) { - /* always prefer UDP */ - th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP); - if (!th) { - th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP); - if (!th) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - } - - rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id, - th->lower_transport); - if (!rtp_c) { - rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH); - return; - } - - /* open input stream */ - if (open_input_stream(rtp_c, "") < 0) { - rtsp_reply_error(c, RTSP_STATUS_INTERNAL); - return; - } - } - - /* test if stream is OK (test needed because several SETUP needs - * to be done for a given file) */ - if (rtp_c->stream != stream) { - rtsp_reply_error(c, RTSP_STATUS_SERVICE); - return; - } - - /* test if stream is already set up */ - if (rtp_c->rtp_ctx[stream_index]) { - rtsp_reply_error(c, RTSP_STATUS_STATE); - return; - } - - /* check transport */ - th = find_transport(h, rtp_c->rtp_protocol); - if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP && - th->client_port_min <= 0)) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - - /* setup default options */ - setup.transport_option[0] = '\0'; - dest_addr = rtp_c->from_addr; - dest_addr.sin_port = htons(th->client_port_min); - - /* setup stream */ - if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - - /* now everything is OK, so we can send the connection parameters */ - rtsp_reply_header(c, RTSP_STATUS_OK); - /* session ID */ - avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); - - switch(rtp_c->rtp_protocol) { - case RTSP_LOWER_TRANSPORT_UDP: - rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]); - rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]); - avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;" - "client_port=%d-%d;server_port=%d-%d", - th->client_port_min, th->client_port_max, - rtp_port, rtcp_port); - break; - case RTSP_LOWER_TRANSPORT_TCP: - avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d", - stream_index * 2, stream_index * 2 + 1); - break; - default: - break; - } - if (setup.transport_option[0] != '\0') - avio_printf(c->pb, ";%s", setup.transport_option); - avio_printf(c->pb, "\r\n"); - - - avio_printf(c->pb, "\r\n"); -} - - -/** - * find an RTP connection by using the session ID. Check consistency - * with filename - */ -static HTTPContext *find_rtp_session_with_url(const char *url, - const char *session_id) -{ - HTTPContext *rtp_c; - char path1[1024]; - const char *path; - char buf[1024]; - int s, len; - - rtp_c = find_rtp_session(session_id); - if (!rtp_c) - return NULL; - - /* find which URL is asked */ - av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); - path = path1; - if (*path == '/') - path++; - if(!strcmp(path, rtp_c->stream->filename)) return rtp_c; - for(s=0; sstream->nb_streams; ++s) { - snprintf(buf, sizeof(buf), "%s/streamid=%d", - rtp_c->stream->filename, s); - if(!strncmp(path, buf, sizeof(buf))) - /* XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE - * if nb_streams>1? */ - return rtp_c; - } - len = strlen(path); - if (len > 0 && path[len - 1] == '/' && - !strncmp(path, rtp_c->stream->filename, len - 1)) - return rtp_c; - return NULL; -} - -static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h) -{ - HTTPContext *rtp_c; - - rtp_c = find_rtp_session_with_url(url, h->session_id); - if (!rtp_c) { - rtsp_reply_error(c, RTSP_STATUS_SESSION); - return; - } - - if (rtp_c->state != HTTPSTATE_SEND_DATA && - rtp_c->state != HTTPSTATE_WAIT_FEED && - rtp_c->state != HTTPSTATE_READY) { - rtsp_reply_error(c, RTSP_STATUS_STATE); - return; - } - - rtp_c->state = HTTPSTATE_SEND_DATA; - - /* now everything is OK, so we can send the connection parameters */ - rtsp_reply_header(c, RTSP_STATUS_OK); - /* session ID */ - avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); - avio_printf(c->pb, "\r\n"); -} - -static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, - RTSPMessageHeader *h, int pause_only) -{ - HTTPContext *rtp_c; - - rtp_c = find_rtp_session_with_url(url, h->session_id); - if (!rtp_c) { - rtsp_reply_error(c, RTSP_STATUS_SESSION); - return; - } - - if (pause_only) { - if (rtp_c->state != HTTPSTATE_SEND_DATA && - rtp_c->state != HTTPSTATE_WAIT_FEED) { - rtsp_reply_error(c, RTSP_STATUS_STATE); - return; - } - rtp_c->state = HTTPSTATE_READY; - rtp_c->first_pts = AV_NOPTS_VALUE; - } - - /* now everything is OK, so we can send the connection parameters */ - rtsp_reply_header(c, RTSP_STATUS_OK); - /* session ID */ - avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); - avio_printf(c->pb, "\r\n"); - - if (!pause_only) - close_connection(rtp_c); -} - -/********************************************************************/ -/* RTP handling */ - -static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, - FFServerStream *stream, - const char *session_id, - enum RTSPLowerTransport rtp_protocol) -{ - HTTPContext *c = NULL; - const char *proto_str; - - /* XXX: should output a warning page when coming - * close to the connection limit */ - if (nb_connections >= config.nb_max_connections) - goto fail; - - /* add a new connection */ - c = av_mallocz(sizeof(HTTPContext)); - if (!c) - goto fail; - - c->fd = -1; - c->poll_entry = NULL; - c->from_addr = *from_addr; - c->buffer_size = IOBUFFER_INIT_SIZE; - c->buffer = av_malloc(c->buffer_size); - if (!c->buffer) - goto fail; - nb_connections++; - c->stream = stream; - av_strlcpy(c->session_id, session_id, sizeof(c->session_id)); - c->state = HTTPSTATE_READY; - c->is_packetized = 1; - c->rtp_protocol = rtp_protocol; - - /* protocol is shown in statistics */ - switch(c->rtp_protocol) { - case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: - proto_str = "MCAST"; - break; - case RTSP_LOWER_TRANSPORT_UDP: - proto_str = "UDP"; - break; - case RTSP_LOWER_TRANSPORT_TCP: - proto_str = "TCP"; - break; - default: - proto_str = "???"; - break; - } - av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol)); - av_strlcat(c->protocol, proto_str, sizeof(c->protocol)); - - current_bandwidth += stream->bandwidth; - - c->next = first_http_ctx; - first_http_ctx = c; - return c; - - fail: - if (c) { - av_freep(&c->buffer); - av_free(c); - } - return NULL; -} - -/** - * add a new RTP stream in an RTP connection (used in RTSP SETUP - * command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is - * used. - */ -static int rtp_new_av_stream(HTTPContext *c, - int stream_index, struct sockaddr_in *dest_addr, - HTTPContext *rtsp_c) -{ - AVFormatContext *ctx; - AVStream *st; - char *ipaddr; - URLContext *h = NULL; - uint8_t *dummy_buf; - int max_packet_size; - void *st_internal; - - /* now we can open the relevant output stream */ - ctx = avformat_alloc_context(); - if (!ctx) - return -1; - ctx->oformat = av_guess_format("rtp", NULL, NULL); - - st = avformat_new_stream(ctx, NULL); - if (!st) - goto fail; - - st_internal = st->internal; - - if (!c->stream->feed || - c->stream->feed == c->stream) - unlayer_stream(st, c->stream->streams[stream_index]); - else - unlayer_stream(st, - c->stream->feed->streams[c->stream->feed_streams[stream_index]]); - av_assert0(st->priv_data == NULL); - av_assert0(st->internal == st_internal); - - /* build destination RTP address */ - ipaddr = inet_ntoa(dest_addr->sin_addr); - - switch(c->rtp_protocol) { - case RTSP_LOWER_TRANSPORT_UDP: - case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: - /* RTP/UDP case */ - - /* XXX: also pass as parameter to function ? */ - if (c->stream->is_multicast) { - int ttl; - ttl = c->stream->multicast_ttl; - if (!ttl) - ttl = 16; - snprintf(ctx->filename, sizeof(ctx->filename), - "rtp://%s:%d?multicast=1&ttl=%d", - ipaddr, ntohs(dest_addr->sin_port), ttl); - } else { - snprintf(ctx->filename, sizeof(ctx->filename), - "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port)); - } - - if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0) - goto fail; - c->rtp_handles[stream_index] = h; - max_packet_size = h->max_packet_size; - break; - case RTSP_LOWER_TRANSPORT_TCP: - /* RTP/TCP case */ - c->rtsp_c = rtsp_c; - max_packet_size = RTSP_TCP_MAX_PACKET_SIZE; - break; - default: - goto fail; - } - - http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n", - ipaddr, ntohs(dest_addr->sin_port), - c->stream->filename, stream_index, c->protocol); - - /* normally, no packets should be output here, but the packet size may - * be checked */ - if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) - /* XXX: close stream */ - goto fail; - - if (avformat_write_header(ctx, NULL) < 0) { - fail: - if (h) - ffurl_close(h); - av_free(st); - av_free(ctx); - return -1; - } - avio_close_dyn_buf(ctx->pb, &dummy_buf); - ctx->pb = NULL; - av_free(dummy_buf); - - c->rtp_ctx[stream_index] = ctx; - return 0; -} - -/********************************************************************/ -/* ffserver initialization */ - -/* FIXME: This code should use avformat_new_stream() */ -static LayeredAVStream *add_av_stream1(FFServerStream *stream, - AVCodecContext *codec, int copy) -{ - LayeredAVStream *fst; - - if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams)) - return NULL; - - fst = av_mallocz(sizeof(*fst)); - if (!fst) - return NULL; - if (copy) { - fst->codec = avcodec_alloc_context3(codec->codec); - if (!fst->codec) { - av_free(fst); - return NULL; - } - avcodec_copy_context(fst->codec, codec); - } else - /* live streams must use the actual feed's codec since it may be - * updated later to carry extradata needed by them. - */ - fst->codec = codec; - - //NOTE we previously allocated internal & internal->avctx, these seemed uneeded though - fst->codecpar = avcodec_parameters_alloc(); - fst->index = stream->nb_streams; - fst->time_base = codec->time_base; - fst->pts_wrap_bits = 33; - fst->sample_aspect_ratio = codec->sample_aspect_ratio; - stream->streams[stream->nb_streams++] = fst; - return fst; -} - -/* return the stream number in the feed */ -static int add_av_stream(FFServerStream *feed, LayeredAVStream *st) -{ - LayeredAVStream *fst; - AVCodecContext *av, *av1; - int i; - - av = st->codec; - for(i=0;inb_streams;i++) { - av1 = feed->streams[i]->codec; - if (av1->codec_id == av->codec_id && - av1->codec_type == av->codec_type && - av1->bit_rate == av->bit_rate) { - - switch(av->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (av1->channels == av->channels && - av1->sample_rate == av->sample_rate) - return i; - break; - case AVMEDIA_TYPE_VIDEO: - if (av1->width == av->width && - av1->height == av->height && - av1->time_base.den == av->time_base.den && - av1->time_base.num == av->time_base.num && - av1->gop_size == av->gop_size) - return i; - break; - default: - abort(); - } - } - } - - fst = add_av_stream1(feed, av, 0); - if (!fst) - return -1; - if (st->recommended_encoder_configuration) - fst->recommended_encoder_configuration = - av_strdup(st->recommended_encoder_configuration); - return feed->nb_streams - 1; -} - -static void remove_stream(FFServerStream *stream) -{ - FFServerStream **ps; - ps = &config.first_stream; - while (*ps) { - if (*ps == stream) - *ps = (*ps)->next; - else - ps = &(*ps)->next; - } -} - -/* compute the needed AVStream for each file */ -static void build_file_streams(void) -{ - FFServerStream *stream; - AVFormatContext *infile; - int i, ret; - - /* gather all streams */ - for(stream = config.first_stream; stream; stream = stream->next) { - infile = NULL; - - if (stream->stream_type != STREAM_TYPE_LIVE || stream->feed) - continue; - - /* the stream comes from a file */ - /* try to open the file */ - /* open stream */ - - - /* specific case: if transport stream output to RTP, - * we use a raw transport stream reader */ - if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) - av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0); - - if (!stream->feed_filename[0]) { - http_log("Unspecified feed file for stream '%s'\n", - stream->filename); - goto fail; - } - - http_log("Opening feed file '%s' for stream '%s'\n", - stream->feed_filename, stream->filename); - - ret = avformat_open_input(&infile, stream->feed_filename, - stream->ifmt, &stream->in_opts); - if (ret < 0) { - http_log("Could not open '%s': %s\n", stream->feed_filename, - av_err2str(ret)); - /* remove stream (no need to spend more time on it) */ - fail: - remove_stream(stream); - } else { - /* find all the AVStreams inside and reference them in - * 'stream' */ - if (avformat_find_stream_info(infile, NULL) < 0) { - http_log("Could not find codec parameters from '%s'\n", - stream->feed_filename); - avformat_close_input(&infile); - goto fail; - } - - for(i=0;inb_streams;i++) - add_av_stream1(stream, infile->streams[i]->codec, 1); - - avformat_close_input(&infile); - } - } -} - -static inline -int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream) -{ - int matches = 1; - -/* FIXME: Missed check on AVCodecContext.flags */ -#define CHECK_CODEC(x) (ccf->codecpar->x != ccs->codecpar->x) - if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) { - http_log("Codecs do not match for stream %d\n", stream); - matches = 0; - } else if (CHECK_CODEC(bit_rate)) { - http_log("Codec bitrates do not match for stream %d\n", stream); - matches = 0; - } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - if (av_cmp_q(ccf->time_base, ccs->time_base) || - CHECK_CODEC(width) || CHECK_CODEC(height)) { - http_log("Codec width, height or framerate do not match for stream %d\n", stream); - matches = 0; - } - } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - if (CHECK_CODEC(sample_rate) || - CHECK_CODEC(channels) || - CHECK_CODEC(frame_size)) { - http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", stream); - matches = 0; - } - } else { - http_log("Unknown codec type for stream %d\n", stream); - matches = 0; - } - - return matches; -} - -/* compute the needed AVStream for each feed */ -static int build_feed_streams(void) -{ - FFServerStream *stream, *feed; - int i, fd; - - /* gather all streams */ - for(stream = config.first_stream; stream; stream = stream->next) { - feed = stream->feed; - if (!feed) - continue; - - if (stream->is_feed) { - for(i=0;inb_streams;i++) - stream->feed_streams[i] = i; - continue; - } - /* we handle a stream coming from a feed */ - for(i=0;inb_streams;i++) - stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]); - } - - /* create feed files if needed */ - for(feed = config.first_feed; feed; feed = feed->next_feed) { - - if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) { - AVFormatContext *s = NULL; - int matches = 0; - - /* See if it matches */ - - if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) < 0) { - http_log("Deleting feed file '%s' as it appears " - "to be corrupt\n", - feed->feed_filename); - goto drop; - } - - /* set buffer size */ - if (ffio_set_buf_size(s->pb, FFM_PACKET_SIZE) < 0) { - http_log("Failed to set buffer size\n"); - avformat_close_input(&s); - goto bail; - } - - /* Now see if it matches */ - if (s->nb_streams != feed->nb_streams) { - http_log("Deleting feed file '%s' as stream counts " - "differ (%d != %d)\n", - feed->feed_filename, s->nb_streams, feed->nb_streams); - goto drop; - } - - matches = 1; - for(i=0;inb_streams;i++) { - AVStream *ss; - LayeredAVStream *sf; - - sf = feed->streams[i]; - ss = s->streams[i]; - - if (sf->index != ss->index || sf->id != ss->id) { - http_log("Index & Id do not match for stream %d (%s)\n", - i, feed->feed_filename); - matches = 0; - break; - } - - matches = check_codec_match (sf, ss, i); - if (!matches) - break; - } - -drop: - if (s) - avformat_close_input(&s); - - if (!matches) { - if (feed->readonly) { - http_log("Unable to delete read-only feed file '%s'\n", - feed->feed_filename); - goto bail; - } - unlink(feed->feed_filename); - } - } - - if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) { - AVFormatContext *s = avformat_alloc_context(); - - if (!s) { - http_log("Failed to allocate context\n"); - goto bail; - } - - if (feed->readonly) { - http_log("Unable to create feed file '%s' as it is " - "marked readonly\n", - feed->feed_filename); - avformat_free_context(s); - goto bail; - } - - /* only write the header of the ffm file */ - if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) { - http_log("Could not open output feed file '%s'\n", - feed->feed_filename); - avformat_free_context(s); - goto bail; - } - s->oformat = feed->fmt; - for (i = 0; inb_streams; i++) { - AVStream *st = avformat_new_stream(s, NULL); // FIXME free this - if (!st) { - http_log("Failed to allocate stream\n"); - goto bail; - } - unlayer_stream(st, feed->streams[i]); - } - if (avformat_write_header(s, NULL) < 0) { - http_log("Container doesn't support the required parameters\n"); - avio_closep(&s->pb); - s->streams = NULL; - s->nb_streams = 0; - avformat_free_context(s); - goto bail; - } - /* XXX: need better API */ - av_freep(&s->priv_data); - avio_closep(&s->pb); - s->streams = NULL; - s->nb_streams = 0; - avformat_free_context(s); - } - - /* get feed size and write index */ - fd = open(feed->feed_filename, O_RDONLY); - if (fd < 0) { - http_log("Could not open output feed file '%s'\n", - feed->feed_filename); - goto bail; - } - - feed->feed_write_index = FFMAX(ffm_read_write_index(fd), - FFM_PACKET_SIZE); - feed->feed_size = lseek(fd, 0, SEEK_END); - /* ensure that we do not wrap before the end of file */ - if (feed->feed_max_size && feed->feed_max_size < feed->feed_size) - feed->feed_max_size = feed->feed_size; - - close(fd); - } - return 0; - -bail: - return -1; -} - -/* compute the bandwidth used by each stream */ -static void compute_bandwidth(void) -{ - unsigned bandwidth; - int i; - FFServerStream *stream; - - for(stream = config.first_stream; stream; stream = stream->next) { - bandwidth = 0; - for(i=0;inb_streams;i++) { - LayeredAVStream *st = stream->streams[i]; - switch(st->codec->codec_type) { - case AVMEDIA_TYPE_AUDIO: - case AVMEDIA_TYPE_VIDEO: - bandwidth += st->codec->bit_rate; - break; - default: - break; - } - } - stream->bandwidth = (bandwidth + 999) / 1000; - } -} - -static void handle_child_exit(int sig) -{ - pid_t pid; - int status; - time_t uptime; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - FFServerStream *feed; - - for (feed = config.first_feed; feed; feed = feed->next) { - if (feed->pid != pid) - continue; - - uptime = time(0) - feed->pid_start; - feed->pid = 0; - fprintf(stderr, - "%s: Pid %"PRId64" exited with status %d after %"PRId64" " - "seconds\n", - feed->filename, (int64_t) pid, status, (int64_t)uptime); - - if (uptime < 30) - /* Turn off any more restarts */ - ffserver_free_child_args(&feed->child_argv); - } - } - - need_to_start_children = 1; -} - -static void opt_debug(void) -{ - config.debug = 1; - snprintf(config.logfilename, sizeof(config.logfilename), "-"); -} - -void show_help_default(const char *opt, const char *arg) -{ - printf("usage: ffserver [options]\n" - "Hyper fast multi format Audio/Video streaming server\n"); - printf("\n"); - show_help_options(options, "Main options:", 0, 0, 0); -} - -static const OptionDef options[] = { - CMDUTILS_COMMON_OPTIONS - { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" }, - { "d", 0, {(void*)opt_debug}, "enable debug mode" }, - { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" }, - { NULL }, -}; - -int main(int argc, char **argv) -{ - struct sigaction sigact = { { 0 } }; - int cfg_parsed; - int ret = EXIT_FAILURE; - - init_dynload(); - - config.filename = av_strdup("/etc/ffserver.conf"); - - parse_loglevel(argc, argv, options); - av_register_all(); - avformat_network_init(); - - show_banner(argc, argv, options); - - my_program_name = argv[0]; - - parse_options(NULL, argc, argv, options, NULL); - - unsetenv("http_proxy"); /* Kill the http_proxy */ - - av_lfg_init(&random_state, av_get_random_seed()); - - sigact.sa_handler = handle_child_exit; - sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART; - sigaction(SIGCHLD, &sigact, 0); - - if ((cfg_parsed = ffserver_parse_ffconfig(config.filename, &config)) < 0) { - fprintf(stderr, "Error reading configuration file '%s': %s\n", - config.filename, av_err2str(cfg_parsed)); - goto bail; - } - - /* open log file if needed */ - if (config.logfilename[0] != '\0') { - if (!strcmp(config.logfilename, "-")) - logfile = stdout; - else - logfile = fopen(config.logfilename, "a"); - av_log_set_callback(http_av_log); - } - - build_file_streams(); - - if (build_feed_streams() < 0) { - http_log("Could not setup feed streams\n"); - goto bail; - } - - compute_bandwidth(); - - /* signal init */ - signal(SIGPIPE, SIG_IGN); - - if (http_server() < 0) { - http_log("Could not start server\n"); - goto bail; - } - - ret=EXIT_SUCCESS; - -bail: - av_freep (&config.filename); - avformat_network_deinit(); - return ret; -} diff --git a/fftools/ffserver_config.c b/fftools/ffserver_config.c deleted file mode 100644 index 54135be98..000000000 --- a/fftools/ffserver_config.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * 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/opt.h" -#include "libavutil/parseutils.h" -#include "libavutil/avstring.h" -#include "libavutil/pixdesc.h" -#include "libavutil/avassert.h" - -#include "cmdutils.h" -#include "ffserver_config.h" - -#define MAX_CHILD_ARGS 64 - -static int ffserver_save_avoption(const char *opt, const char *arg, int type, - FFServerConfig *config); -static void vreport_config_error(const char *filename, int line_num, - int log_level, int *errors, const char *fmt, - va_list vl); -static void report_config_error(const char *filename, int line_num, - int log_level, int *errors, const char *fmt, - ...); - -#define ERROR(...) report_config_error(config->filename, config->line_num,\ - AV_LOG_ERROR, &config->errors, __VA_ARGS__) -#define WARNING(...) report_config_error(config->filename, config->line_num,\ - AV_LOG_WARNING, &config->warnings, __VA_ARGS__) - -/* FIXME: make ffserver work with IPv6 */ -/* resolve host with also IP address parsing */ -static int resolve_host(struct in_addr *sin_addr, const char *hostname) -{ - - if (!ff_inet_aton(hostname, sin_addr)) { -#if HAVE_GETADDRINFO - struct addrinfo *ai, *cur; - struct addrinfo hints = { 0 }; - hints.ai_family = AF_INET; - if (getaddrinfo(hostname, NULL, &hints, &ai)) - return -1; - /* getaddrinfo returns a linked list of addrinfo structs. - * Even if we set ai_family = AF_INET above, make sure - * that the returned one actually is of the correct type. */ - for (cur = ai; cur; cur = cur->ai_next) { - if (cur->ai_family == AF_INET) { - *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr; - freeaddrinfo(ai); - return 0; - } - } - freeaddrinfo(ai); - return -1; -#else - struct hostent *hp; - hp = gethostbyname(hostname); - if (!hp) - return -1; - memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); -#endif - } - return 0; -} - -void ffserver_get_arg(char *buf, int buf_size, const char **pp) -{ - const char *p; - char *q; - int quote = 0; - - p = *pp; - q = buf; - - while (av_isspace(*p)) p++; - - if (*p == '\"' || *p == '\'') - quote = *p++; - - while (*p != '\0') { - if (quote && *p == quote || !quote && av_isspace(*p)) - break; - if ((q - buf) < buf_size - 1) - *q++ = *p; - p++; - } - - *q = '\0'; - if (quote && *p == quote) - p++; - *pp = p; -} - -void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed, - FFServerIPAddressACL *ext_acl, - const char *p, const char *filename, int line_num) -{ - char arg[1024]; - FFServerIPAddressACL acl; - FFServerIPAddressACL *nacl; - FFServerIPAddressACL **naclp; - - ffserver_get_arg(arg, sizeof(arg), &p); - if (av_strcasecmp(arg, "allow") == 0) - acl.action = IP_ALLOW; - else if (av_strcasecmp(arg, "deny") == 0) - acl.action = IP_DENY; - else { - fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n", - filename, line_num, arg); - goto bail; - } - - ffserver_get_arg(arg, sizeof(arg), &p); - - if (resolve_host(&acl.first, arg)) { - fprintf(stderr, - "%s:%d: ACL refers to invalid host or IP address '%s'\n", - filename, line_num, arg); - goto bail; - } - - acl.last = acl.first; - - ffserver_get_arg(arg, sizeof(arg), &p); - - if (arg[0]) { - if (resolve_host(&acl.last, arg)) { - fprintf(stderr, - "%s:%d: ACL refers to invalid host or IP address '%s'\n", - filename, line_num, arg); - goto bail; - } - } - - nacl = av_mallocz(sizeof(*nacl)); - if (!nacl) { - fprintf(stderr, "Failed to allocate FFServerIPAddressACL\n"); - goto bail; - } - - naclp = 0; - - acl.next = 0; - *nacl = acl; - - if (stream) - naclp = &stream->acl; - else if (feed) - naclp = &feed->acl; - else if (ext_acl) - naclp = &ext_acl; - else - fprintf(stderr, "%s:%d: ACL found not in or \n", - filename, line_num); - - if (naclp) { - while (*naclp) - naclp = &(*naclp)->next; - - *naclp = nacl; - } else - av_free(nacl); - -bail: - return; - -} - -/* add a codec and set the default parameters */ -static void add_codec(FFServerStream *stream, AVCodecContext *av, - FFServerConfig *config) -{ - LayeredAVStream *st; - AVDictionary **opts, *recommended = NULL; - char *enc_config; - - if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams)) - return; - - opts = av->codec_type == AVMEDIA_TYPE_AUDIO ? - &config->audio_opts : &config->video_opts; - av_dict_copy(&recommended, *opts, 0); - av_opt_set_dict2(av->priv_data, opts, AV_OPT_SEARCH_CHILDREN); - av_opt_set_dict2(av, opts, AV_OPT_SEARCH_CHILDREN); - - if (av_dict_count(*opts)) - av_log(NULL, AV_LOG_WARNING, - "Something is wrong, %d options are not set!\n", - av_dict_count(*opts)); - - if (!config->stream_use_defaults) { - switch(av->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (av->bit_rate == 0) - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "audio bit rate is not set\n"); - if (av->sample_rate == 0) - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "audio sample rate is not set\n"); - break; - case AVMEDIA_TYPE_VIDEO: - if (av->width == 0 || av->height == 0) - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "video size is not set\n"); - break; - default: - av_assert0(0); - } - goto done; - } - - /* stream_use_defaults = true */ - - /* compute default parameters */ - switch(av->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (!av_dict_get(recommended, "b", NULL, 0)) { - av->bit_rate = 64000; - av_dict_set_int(&recommended, "b", av->bit_rate, 0); - WARNING("Setting default value for audio bit rate = %d. " - "Use NoDefaults to disable it.\n", - av->bit_rate); - } - if (!av_dict_get(recommended, "ar", NULL, 0)) { - av->sample_rate = 22050; - av_dict_set_int(&recommended, "ar", av->sample_rate, 0); - WARNING("Setting default value for audio sample rate = %d. " - "Use NoDefaults to disable it.\n", - av->sample_rate); - } - if (!av_dict_get(recommended, "ac", NULL, 0)) { - av->channels = 1; - av_dict_set_int(&recommended, "ac", av->channels, 0); - WARNING("Setting default value for audio channel count = %d. " - "Use NoDefaults to disable it.\n", - av->channels); - } - break; - case AVMEDIA_TYPE_VIDEO: - if (!av_dict_get(recommended, "b", NULL, 0)) { - av->bit_rate = 64000; - av_dict_set_int(&recommended, "b", av->bit_rate, 0); - WARNING("Setting default value for video bit rate = %d. " - "Use NoDefaults to disable it.\n", - av->bit_rate); - } - if (!av_dict_get(recommended, "time_base", NULL, 0)){ - av->time_base.den = 5; - av->time_base.num = 1; - av_dict_set(&recommended, "time_base", "1/5", 0); - WARNING("Setting default value for video frame rate = %d. " - "Use NoDefaults to disable it.\n", - av->time_base.den); - } - if (!av_dict_get(recommended, "video_size", NULL, 0)) { - av->width = 160; - av->height = 128; - av_dict_set(&recommended, "video_size", "160x128", 0); - WARNING("Setting default value for video size = %dx%d. " - "Use NoDefaults to disable it.\n", - av->width, av->height); - } - /* Bitrate tolerance is less for streaming */ - if (!av_dict_get(recommended, "bt", NULL, 0)) { - av->bit_rate_tolerance = FFMAX(av->bit_rate / 4, - (int64_t)av->bit_rate*av->time_base.num/av->time_base.den); - av_dict_set_int(&recommended, "bt", av->bit_rate_tolerance, 0); - WARNING("Setting default value for video bit rate tolerance = %d. " - "Use NoDefaults to disable it.\n", - av->bit_rate_tolerance); - } - - if (!av_dict_get(recommended, "rc_eq", NULL, 0)) { - av->rc_eq = av_strdup("tex^qComp"); - av_dict_set(&recommended, "rc_eq", "tex^qComp", 0); - WARNING("Setting default value for video rate control equation = " - "%s. Use NoDefaults to disable it.\n", - av->rc_eq); - } - if (!av_dict_get(recommended, "maxrate", NULL, 0)) { - av->rc_max_rate = av->bit_rate * 2; - av_dict_set_int(&recommended, "maxrate", av->rc_max_rate, 0); - WARNING("Setting default value for video max rate = %d. " - "Use NoDefaults to disable it.\n", - av->rc_max_rate); - } - - if (av->rc_max_rate && !av_dict_get(recommended, "bufsize", NULL, 0)) { - av->rc_buffer_size = av->rc_max_rate; - av_dict_set_int(&recommended, "bufsize", av->rc_buffer_size, 0); - WARNING("Setting default value for video buffer size = %d. " - "Use NoDefaults to disable it.\n", - av->rc_buffer_size); - } - break; - default: - abort(); - } - -done: - st = av_mallocz(sizeof(*st)); - if (!st) - return; - av_dict_get_string(recommended, &enc_config, '=', ','); - av_dict_free(&recommended); - st->recommended_encoder_configuration = enc_config; - st->codec = av; - st->codecpar = avcodec_parameters_alloc(); - avcodec_parameters_from_context(st->codecpar, av); - stream->streams[stream->nb_streams++] = st; -} - -static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, - FFServerConfig *config) -{ - int ret; - AVCodec *codec = avcodec_find_encoder_by_name(codec_name); - if (!codec || codec->type != ctx->codec_type) { - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, - "Invalid codec name: '%s'\n", codec_name); - return 0; - } - if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) { - if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0) - return ret; - ctx->codec = codec; - } - if (ctx->codec_id != codec->id) - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, - "Inconsistent configuration: trying to set '%s' " - "codec option, but '%s' codec is used previously\n", - codec_name, avcodec_get_name(ctx->codec_id)); - return 0; -} - -static int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config) -{ - FILE *f=NULL; - char filename[1000], tmp[1000], tmp2[1000], line[1000]; - int ret = 0; - AVCodecContext *avctx; - const AVCodec *codec; - - switch(type) { - case AV_OPT_FLAG_AUDIO_PARAM: - avctx = config->dummy_actx; - break; - case AV_OPT_FLAG_VIDEO_PARAM: - avctx = config->dummy_vctx; - break; - default: - av_assert0(0); - } - codec = avcodec_find_encoder(avctx->codec_id); - - if (!(f = get_preset_file(filename, sizeof(filename), arg, 0, - codec ? codec->name : NULL))) { - av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg); - return AVERROR(EINVAL); - } - - while(!feof(f)){ - int e= fscanf(f, "%999[^\n]\n", line) - 1; - if(line[0] == '#' && !e) - continue; - e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; - if(e){ - av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename, - line); - ret = AVERROR(EINVAL); - break; - } - if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO || - !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO) - { - if (ffserver_set_codec(avctx, tmp2, config) < 0) - break; - } else if (!strcmp(tmp, "scodec")) { - av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n"); - ret = AVERROR(EINVAL); - break; - } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0) - break; - } - - fclose(f); - - return ret; -} - -static AVOutputFormat *ffserver_guess_format(const char *short_name, - const char *filename, - const char *mime_type) -{ - AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type); - - if (fmt) { - AVOutputFormat *stream_fmt; - char stream_format_name[64]; - - snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", - fmt->name); - stream_fmt = av_guess_format(stream_format_name, NULL, NULL); - - if (stream_fmt) - fmt = stream_fmt; - } - - return fmt; -} - -static void vreport_config_error(const char *filename, int line_num, - int log_level, int *errors, const char *fmt, - va_list vl) -{ - av_log(NULL, log_level, "%s:%d: ", filename, line_num); - av_vlog(NULL, log_level, fmt, vl); - if (errors) - (*errors)++; -} - -static void report_config_error(const char *filename, int line_num, - int log_level, int *errors, - const char *fmt, ...) -{ - va_list vl; - va_start(vl, fmt); - vreport_config_error(filename, line_num, log_level, errors, fmt, vl); - va_end(vl); -} - -static int ffserver_set_int_param(int *dest, const char *value, int factor, - int min, int max, FFServerConfig *config, - const char *error_msg, ...) -{ - int tmp; - char *tailp; - if (!value || !value[0]) - goto error; - errno = 0; - tmp = strtol(value, &tailp, 0); - if (tmp < min || tmp > max) - goto error; - if (factor) { - if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor)) - goto error; - tmp *= factor; - } - if (tailp[0] || errno) - goto error; - if (dest) - *dest = tmp; - return 0; - error: - if (config) { - va_list vl; - va_start(vl, error_msg); - vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, error_msg, vl); - va_end(vl); - } - return AVERROR(EINVAL); -} - -static int ffserver_set_float_param(float *dest, const char *value, - float factor, float min, float max, - FFServerConfig *config, - const char *error_msg, ...) -{ - double tmp; - char *tailp; - if (!value || !value[0]) - goto error; - errno = 0; - tmp = strtod(value, &tailp); - if (tmp < min || tmp > max) - goto error; - if (factor) - tmp *= factor; - if (tailp[0] || errno) - goto error; - if (dest) - *dest = tmp; - return 0; - error: - if (config) { - va_list vl; - va_start(vl, error_msg); - vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, error_msg, vl); - va_end(vl); - } - return AVERROR(EINVAL); -} - -static int ffserver_save_avoption(const char *opt, const char *arg, int type, - FFServerConfig *config) -{ - static int hinted = 0; - int ret = 0; - AVDictionaryEntry *e; - const AVOption *o = NULL; - const char *option = NULL; - const char *codec_name = NULL; - char buff[1024]; - AVCodecContext *ctx; - AVDictionary **dict; - enum AVCodecID guessed_codec_id; - - switch (type) { - case AV_OPT_FLAG_VIDEO_PARAM: - ctx = config->dummy_vctx; - dict = &config->video_opts; - guessed_codec_id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ? - config->guessed_video_codec_id : AV_CODEC_ID_H264; - break; - case AV_OPT_FLAG_AUDIO_PARAM: - ctx = config->dummy_actx; - dict = &config->audio_opts; - guessed_codec_id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ? - config->guessed_audio_codec_id : AV_CODEC_ID_AAC; - break; - default: - av_assert0(0); - } - - if (strchr(opt, ':')) { - //explicit private option - snprintf(buff, sizeof(buff), "%s", opt); - codec_name = buff; - if(!(option = strchr(buff, ':'))){ - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "Syntax error. Unmatched ':'\n"); - return -1; - - } - buff[option - buff] = '\0'; - option++; - if ((ret = ffserver_set_codec(ctx, codec_name, config)) < 0) - return ret; - if (!ctx->codec || !ctx->priv_data) - return -1; - } else { - option = opt; - } - - o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, - AV_OPT_SEARCH_CHILDREN); - if (!o && - (!strcmp(option, "time_base") || !strcmp(option, "pixel_format") || - !strcmp(option, "video_size") || !strcmp(option, "codec_tag"))) - o = av_opt_find(ctx, option, NULL, 0, 0); - if (!o) { - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, "Option not found: '%s'\n", opt); - if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) { - hinted = 1; - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, NULL, "If '%s' is a codec private" - "option, then prefix it with codec name, for " - "example '%s:%s %s' or define codec earlier.\n", - opt, avcodec_get_name(guessed_codec_id) ,opt, - arg); - } - } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, "Invalid value for option %s (%s): %s\n", opt, - arg, av_err2str(ret)); - } else if ((e = av_dict_get(*dict, option, NULL, 0))) { - if ((o->type == AV_OPT_TYPE_FLAGS) && arg && - (arg[0] == '+' || arg[0] == '-')) - return av_dict_set(dict, option, arg, AV_DICT_APPEND); - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, "Redeclaring value of option '%s'." - "Previous value was: '%s'.\n", opt, e->value); - } else if (av_dict_set(dict, option, arg, 0) < 0) { - return AVERROR(ENOMEM); - } - return 0; -} - -static int ffserver_save_avoption_int(const char *opt, int64_t arg, - int type, FFServerConfig *config) -{ - char buf[22]; - snprintf(buf, sizeof(buf), "%"PRId64, arg); - return ffserver_save_avoption(opt, buf, type, config); -} - -static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd, - const char **p) -{ - int val; - char arg[1024]; - if (!av_strcasecmp(cmd, "Port") || !av_strcasecmp(cmd, "HTTPPort")) { - if (!av_strcasecmp(cmd, "Port")) - WARNING("Port option is deprecated. Use HTTPPort instead.\n"); - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid port: %s\n", arg); - if (val < 1024) - WARNING("Trying to use IETF assigned system port: '%d'\n", val); - config->http_addr.sin_port = htons(val); - } else if (!av_strcasecmp(cmd, "HTTPBindAddress") || - !av_strcasecmp(cmd, "BindAddress")) { - if (!av_strcasecmp(cmd, "BindAddress")) - WARNING("BindAddress option is deprecated. Use HTTPBindAddress " - "instead.\n"); - ffserver_get_arg(arg, sizeof(arg), p); - if (resolve_host(&config->http_addr.sin_addr, arg)) - ERROR("Invalid host/IP address: '%s'\n", arg); - } else if (!av_strcasecmp(cmd, "NoDaemon")) { - WARNING("NoDaemon option has no effect. You should remove it.\n"); - } else if (!av_strcasecmp(cmd, "RTSPPort")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid port: %s\n", arg); - config->rtsp_addr.sin_port = htons(val); - } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (resolve_host(&config->rtsp_addr.sin_addr, arg)) - ERROR("Invalid host/IP address: %s\n", arg); - } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid MaxHTTPConnections: %s\n", arg); - config->nb_max_http_connections = val; - if (config->nb_max_connections > config->nb_max_http_connections) { - ERROR("Inconsistent configuration: MaxClients(%d) > " - "MaxHTTPConnections(%d)\n", config->nb_max_connections, - config->nb_max_http_connections); - } - } else if (!av_strcasecmp(cmd, "MaxClients")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid MaxClients: '%s'\n", arg); - config->nb_max_connections = val; - if (config->nb_max_connections > config->nb_max_http_connections) { - ERROR("Inconsistent configuration: MaxClients(%d) > " - "MaxHTTPConnections(%d)\n", config->nb_max_connections, - config->nb_max_http_connections); - } - } else if (!av_strcasecmp(cmd, "MaxBandwidth")) { - int64_t llval; - char *tailp; - ffserver_get_arg(arg, sizeof(arg), p); - errno = 0; - llval = strtoll(arg, &tailp, 10); - if (llval < 10 || llval > 10000000 || tailp[0] || errno) - ERROR("Invalid MaxBandwidth: '%s'\n", arg); - else - config->max_bandwidth = llval; - } else if (!av_strcasecmp(cmd, "CustomLog")) { - if (!config->debug) { - ffserver_get_arg(config->logfilename, sizeof(config->logfilename), - p); - } - } else if (!av_strcasecmp(cmd, "LoadModule")) { - ERROR("Loadable modules are no longer supported\n"); - } else if (!av_strcasecmp(cmd, "NoDefaults")) { - config->use_defaults = 0; - } else if (!av_strcasecmp(cmd, "UseDefaults")) { - config->use_defaults = 1; - } else - ERROR("Incorrect keyword: '%s'\n", cmd); - return 0; -} - -static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, - const char **p, FFServerStream **pfeed) -{ - FFServerStream *feed; - char arg[1024]; - av_assert0(pfeed); - feed = *pfeed; - if (!av_strcasecmp(cmd, "filename, sizeof(feed->filename), p); - q = strrchr(feed->filename, '>'); - if (*q) - *q = '\0'; - - for (s = config->first_feed; s; s = s->next) { - if (!strcmp(feed->filename, s->filename)) - ERROR("Feed '%s' already registered\n", s->filename); - } - - feed->fmt = av_guess_format("ffm", NULL, NULL); - /* default feed file */ - snprintf(feed->feed_filename, sizeof(feed->feed_filename), - "/tmp/%s.ffm", feed->filename); - feed->feed_max_size = 5 * 1024 * 1024; - feed->is_feed = 1; - feed->feed = feed; /* self feeding :-) */ - *pfeed = feed; - return 0; - } - av_assert0(feed); - if (!av_strcasecmp(cmd, "Launch")) { - int i; - - feed->child_argv = av_mallocz_array(MAX_CHILD_ARGS, sizeof(char *)); - if (!feed->child_argv) - return AVERROR(ENOMEM); - for (i = 0; i < MAX_CHILD_ARGS - 2; i++) { - ffserver_get_arg(arg, sizeof(arg), p); - if (!arg[0]) - break; - - feed->child_argv[i] = av_strdup(arg); - if (!feed->child_argv[i]) - return AVERROR(ENOMEM); - } - - feed->child_argv[i] = - av_asprintf("http://%s:%d/%s", - (config->http_addr.sin_addr.s_addr == INADDR_ANY) ? - "127.0.0.1" : inet_ntoa(config->http_addr.sin_addr), - ntohs(config->http_addr.sin_port), feed->filename); - if (!feed->child_argv[i]) - return AVERROR(ENOMEM); - } else if (!av_strcasecmp(cmd, "ACL")) { - ffserver_parse_acl_row(NULL, feed, NULL, *p, config->filename, - config->line_num); - } else if (!av_strcasecmp(cmd, "File") || - !av_strcasecmp(cmd, "ReadOnlyFile")) { - ffserver_get_arg(feed->feed_filename, sizeof(feed->feed_filename), p); - feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile"); - } else if (!av_strcasecmp(cmd, "Truncate")) { - ffserver_get_arg(arg, sizeof(arg), p); - /* assume Truncate is true in case no argument is specified */ - if (!arg[0]) { - feed->truncate = 1; - } else { - WARNING("Truncate N syntax in configuration file is deprecated. " - "Use Truncate alone with no arguments.\n"); - feed->truncate = strtod(arg, NULL); - } - } else if (!av_strcasecmp(cmd, "FileMaxSize")) { - char *p1; - double fsize; - - ffserver_get_arg(arg, sizeof(arg), p); - p1 = arg; - fsize = strtod(p1, &p1); - switch(av_toupper(*p1)) { - case 'K': - fsize *= 1024; - break; - case 'M': - fsize *= 1024 * 1024; - break; - case 'G': - fsize *= 1024 * 1024 * 1024; - break; - default: - ERROR("Invalid file size: '%s'\n", arg); - break; - } - feed->feed_max_size = (int64_t)fsize; - if (feed->feed_max_size < FFM_PACKET_SIZE*4) { - ERROR("Feed max file size is too small. Must be at least %d.\n", - FFM_PACKET_SIZE*4); - } - } else if (!av_strcasecmp(cmd, "")) { - *pfeed = NULL; - } else { - ERROR("Invalid entry '%s' inside \n", cmd); - } - return 0; -} - -static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, - const char **p, - FFServerStream **pstream) -{ - char arg[1024], arg2[1024]; - FFServerStream *stream; - int val; - - av_assert0(pstream); - stream = *pstream; - - if (!av_strcasecmp(cmd, "dummy_actx = avcodec_alloc_context3(NULL); - config->dummy_vctx = avcodec_alloc_context3(NULL); - if (!config->dummy_vctx || !config->dummy_actx) { - av_free(stream); - avcodec_free_context(&config->dummy_vctx); - avcodec_free_context(&config->dummy_actx); - return AVERROR(ENOMEM); - } - config->dummy_actx->codec_type = AVMEDIA_TYPE_AUDIO; - config->dummy_vctx->codec_type = AVMEDIA_TYPE_VIDEO; - ffserver_get_arg(stream->filename, sizeof(stream->filename), p); - q = strrchr(stream->filename, '>'); - if (q) - *q = '\0'; - - for (s = config->first_stream; s; s = s->next) { - if (!strcmp(stream->filename, s->filename)) - ERROR("Stream '%s' already registered\n", s->filename); - } - - stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL); - if (stream->fmt) { - config->guessed_audio_codec_id = stream->fmt->audio_codec; - config->guessed_video_codec_id = stream->fmt->video_codec; - } else { - config->guessed_audio_codec_id = AV_CODEC_ID_NONE; - config->guessed_video_codec_id = AV_CODEC_ID_NONE; - } - config->stream_use_defaults = config->use_defaults; - *pstream = stream; - return 0; - } - av_assert0(stream); - if (!av_strcasecmp(cmd, "Feed")) { - FFServerStream *sfeed; - ffserver_get_arg(arg, sizeof(arg), p); - sfeed = config->first_feed; - while (sfeed) { - if (!strcmp(sfeed->filename, arg)) - break; - sfeed = sfeed->next_feed; - } - if (!sfeed) - ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, - stream->filename); - else - stream->feed = sfeed; - } else if (!av_strcasecmp(cmd, "Format")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (!strcmp(arg, "status")) { - stream->stream_type = STREAM_TYPE_STATUS; - stream->fmt = NULL; - } else { - stream->stream_type = STREAM_TYPE_LIVE; - /* JPEG cannot be used here, so use single frame MJPEG */ - if (!strcmp(arg, "jpeg")) { - strcpy(arg, "singlejpeg"); - stream->single_frame=1; - } - stream->fmt = ffserver_guess_format(arg, NULL, NULL); - if (!stream->fmt) - ERROR("Unknown Format: '%s'\n", arg); - } - if (stream->fmt) { - config->guessed_audio_codec_id = stream->fmt->audio_codec; - config->guessed_video_codec_id = stream->fmt->video_codec; - } - } else if (!av_strcasecmp(cmd, "InputFormat")) { - ffserver_get_arg(arg, sizeof(arg), p); - stream->ifmt = av_find_input_format(arg); - if (!stream->ifmt) - ERROR("Unknown input format: '%s'\n", arg); - } else if (!av_strcasecmp(cmd, "FaviconURL")) { - if (stream->stream_type == STREAM_TYPE_STATUS) - ffserver_get_arg(stream->feed_filename, - sizeof(stream->feed_filename), p); - else - ERROR("FaviconURL only permitted for status streams\n"); - } else if (!av_strcasecmp(cmd, "Author") || - !av_strcasecmp(cmd, "Comment") || - !av_strcasecmp(cmd, "Copyright") || - !av_strcasecmp(cmd, "Title")) { - char key[32]; - int i; - ffserver_get_arg(arg, sizeof(arg), p); - for (i = 0; i < strlen(cmd); i++) - key[i] = av_tolower(cmd[i]); - key[i] = 0; - WARNING("Deprecated '%s' option in configuration file. Use " - "'Metadata %s VALUE' instead.\n", cmd, key); - if (av_dict_set(&stream->metadata, key, arg, 0) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Metadata")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_get_arg(arg2, sizeof(arg2), p); - if (av_dict_set(&stream->metadata, arg, arg2, 0) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Preroll")) { - ffserver_get_arg(arg, sizeof(arg), p); - stream->prebuffer = atof(arg) * 1000; - } else if (!av_strcasecmp(cmd, "StartSendOnKey")) { - stream->send_on_key = 1; - } else if (!av_strcasecmp(cmd, "AudioCodec")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_codec(config->dummy_actx, arg, config); - } else if (!av_strcasecmp(cmd, "VideoCodec")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_codec(config->dummy_vctx, arg, config); - } else if (!av_strcasecmp(cmd, "MaxTime")) { - ffserver_get_arg(arg, sizeof(arg), p); - stream->max_time = atof(arg) * 1000; - } else if (!av_strcasecmp(cmd, "AudioBitRate")) { - float f; - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_float_param(&f, arg, 1000, -FLT_MAX, FLT_MAX, config, - "Invalid %s: '%s'\n", cmd, arg); - if (ffserver_save_avoption_int("b", (int64_t)lrintf(f), - AV_OPT_FLAG_AUDIO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AudioChannels")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("ac", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AudioSampleRate")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("ar", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) { - int minrate, maxrate; - char *dash; - ffserver_get_arg(arg, sizeof(arg), p); - dash = strchr(arg, '-'); - if (dash) { - *dash = '\0'; - dash++; - if (ffserver_set_int_param(&minrate, arg, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0 && - ffserver_set_int_param(&maxrate, dash, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0) { - if (ffserver_save_avoption_int("minrate", minrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || - ffserver_save_avoption_int("maxrate", maxrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } - } else - ERROR("Incorrect format for VideoBitRateRange. It should be " - "-: '%s'.\n", arg); - } else if (!av_strcasecmp(cmd, "Debug")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("debug", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 || - ffserver_save_avoption("debug", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Strict")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("strict", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 || - ffserver_save_avoption("strict", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBufferSize")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 8*1024, 0, INT_MAX, config, - "Invalid %s: '%s'", cmd, arg); - if (ffserver_save_avoption_int("bufsize", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config, - "Invalid %s: '%s'", cmd, arg); - if (ffserver_save_avoption_int("bt", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBitRate")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config, - "Invalid %s: '%s'", cmd, arg); - if (ffserver_save_avoption_int("b", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoSize")) { - int ret, w, h; - ffserver_get_arg(arg, sizeof(arg), p); - ret = av_parse_video_size(&w, &h, arg); - if (ret < 0) - ERROR("Invalid video size '%s'\n", arg); - else { - if (w % 2 || h % 2) - WARNING("Image size is not a multiple of 2\n"); - if (ffserver_save_avoption("video_size", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } - } else if (!av_strcasecmp(cmd, "VideoFrameRate")) { - ffserver_get_arg(&arg[2], sizeof(arg) - 2, p); - arg[0] = '1'; arg[1] = '/'; - if (ffserver_save_avoption("time_base", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "PixelFormat")) { - enum AVPixelFormat pix_fmt; - ffserver_get_arg(arg, sizeof(arg), p); - pix_fmt = av_get_pix_fmt(arg); - if (pix_fmt == AV_PIX_FMT_NONE) - ERROR("Unknown pixel format: '%s'\n", arg); - else if (ffserver_save_avoption("pixel_format", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoGopSize")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("g", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) { - if (ffserver_save_avoption("g", "1", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoHighQuality")) { - if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Video4MotionVector")) { - if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || //FIXME remove - ffserver_save_avoption("flags", "+mv4", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AVOptionVideo") || - !av_strcasecmp(cmd, "AVOptionAudio")) { - int ret; - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_get_arg(arg2, sizeof(arg2), p); - if (!av_strcasecmp(cmd, "AVOptionVideo")) - ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_VIDEO_PARAM, - config); - else - ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_AUDIO_PARAM, - config); - if (ret < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AVPresetVideo") || - !av_strcasecmp(cmd, "AVPresetAudio")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (!av_strcasecmp(cmd, "AVPresetVideo")) - ffserver_opt_preset(arg, AV_OPT_FLAG_VIDEO_PARAM, config); - else - ffserver_opt_preset(arg, AV_OPT_FLAG_AUDIO_PARAM, config); - } else if (!av_strcasecmp(cmd, "VideoTag")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (strlen(arg) == 4 && - ffserver_save_avoption_int("codec_tag", - MKTAG(arg[0], arg[1], arg[2], arg[3]), - AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "BitExact")) { - config->bitexact = 1; - if (ffserver_save_avoption("flags", "+bitexact", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "DctFastint")) { - if (ffserver_save_avoption("dct", "fastint", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "IdctSimple")) { - if (ffserver_save_avoption("idct", "simple", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Qscale")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config, - "Invalid Qscale: '%s'\n", arg); - if (ffserver_save_avoption("flags", "+qscale", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || - ffserver_save_avoption_int("global_quality", FF_QP2LAMBDA * val, - AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoQDiff")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("qdiff", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoQMax")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("qmax", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoQMin")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("qmin", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "LumiMask")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("lumi_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "DarkMask")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("dark_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "NoVideo")) { - config->no_video = 1; - } else if (!av_strcasecmp(cmd, "NoAudio")) { - config->no_audio = 1; - } else if (!av_strcasecmp(cmd, "ACL")) { - ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename, - config->line_num); - } else if (!av_strcasecmp(cmd, "DynamicACL")) { - ffserver_get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), p); - } else if (!av_strcasecmp(cmd, "RTSPOption")) { - ffserver_get_arg(arg, sizeof(arg), p); - av_freep(&stream->rtsp_option); - stream->rtsp_option = av_strdup(arg); - } else if (!av_strcasecmp(cmd, "MulticastAddress")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (resolve_host(&stream->multicast_ip, arg)) - ERROR("Invalid host/IP address: '%s'\n", arg); - stream->is_multicast = 1; - stream->loop = 1; /* default is looping */ - } else if (!av_strcasecmp(cmd, "MulticastPort")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid MulticastPort: '%s'\n", arg); - stream->multicast_port = val; - } else if (!av_strcasecmp(cmd, "MulticastTTL")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config, - "Invalid MulticastTTL: '%s'\n", arg); - stream->multicast_ttl = val; - } else if (!av_strcasecmp(cmd, "NoLoop")) { - stream->loop = 0; - } else if (!av_strcasecmp(cmd, "")) { - config->stream_use_defaults &= 1; - if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) { - if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE) - config->dummy_actx->codec_id = config->guessed_audio_codec_id; - if (!config->no_audio && - config->dummy_actx->codec_id != AV_CODEC_ID_NONE) { - AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_actx->codec_id)); - add_codec(stream, audio_enc, config); - } - if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE) - config->dummy_vctx->codec_id = config->guessed_video_codec_id; - if (!config->no_video && - config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) { - AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_vctx->codec_id)); - add_codec(stream, video_enc, config); - } - } - av_dict_free(&config->video_opts); - av_dict_free(&config->audio_opts); - avcodec_free_context(&config->dummy_vctx); - avcodec_free_context(&config->dummy_actx); - config->no_video = 0; - config->no_audio = 0; - *pstream = NULL; - } else if (!av_strcasecmp(cmd, "File") || - !av_strcasecmp(cmd, "ReadOnlyFile")) { - ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), - p); - } else if (!av_strcasecmp(cmd, "UseDefaults")) { - if (config->stream_use_defaults > 1) - WARNING("Multiple UseDefaults/NoDefaults entries.\n"); - config->stream_use_defaults = 3; - } else if (!av_strcasecmp(cmd, "NoDefaults")) { - if (config->stream_use_defaults > 1) - WARNING("Multiple UseDefaults/NoDefaults entries.\n"); - config->stream_use_defaults = 2; - } else { - ERROR("Invalid entry '%s' inside \n", cmd); - } - return 0; - nomem: - av_log(NULL, AV_LOG_ERROR, "Out of memory. Aborting.\n"); - av_dict_free(&config->video_opts); - av_dict_free(&config->audio_opts); - avcodec_free_context(&config->dummy_vctx); - avcodec_free_context(&config->dummy_actx); - return AVERROR(ENOMEM); -} - -static int ffserver_parse_config_redirect(FFServerConfig *config, - const char *cmd, const char **p, - FFServerStream **predirect) -{ - FFServerStream *redirect; - av_assert0(predirect); - redirect = *predirect; - - if (!av_strcasecmp(cmd, "filename, sizeof(redirect->filename), p); - q = strrchr(redirect->filename, '>'); - if (*q) - *q = '\0'; - redirect->stream_type = STREAM_TYPE_REDIRECT; - *predirect = redirect; - return 0; - } - av_assert0(redirect); - if (!av_strcasecmp(cmd, "URL")) { - ffserver_get_arg(redirect->feed_filename, - sizeof(redirect->feed_filename), p); - } else if (!av_strcasecmp(cmd, "
")) { - if (!redirect->feed_filename[0]) - ERROR("No URL found for \n"); - *predirect = NULL; - } else { - ERROR("Invalid entry '%s' inside \n", cmd); - } - return 0; -} - -int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config) -{ - FILE *f; - char line[1024]; - char cmd[64]; - const char *p; - FFServerStream **last_stream, *stream = NULL, *redirect = NULL; - FFServerStream **last_feed, *feed = NULL; - int ret = 0; - - av_assert0(config); - - f = fopen(filename, "r"); - if (!f) { - ret = AVERROR(errno); - av_log(NULL, AV_LOG_ERROR, - "Could not open the configuration file '%s'\n", filename); - return ret; - } - - config->first_stream = NULL; - config->first_feed = NULL; - config->errors = config->warnings = 0; - - last_stream = &config->first_stream; - last_feed = &config->first_feed; - - config->line_num = 0; - while (fgets(line, sizeof(line), f) != NULL) { - config->line_num++; - p = line; - while (av_isspace(*p)) - p++; - if (*p == '\0' || *p == '#') - continue; - - ffserver_get_arg(cmd, sizeof(cmd), &p); - - if (feed || !av_strcasecmp(cmd, "next; - last_feed = &feed->next_feed; - } - } - } else if (stream || !av_strcasecmp(cmd, "next; - } - } - } else if (redirect || !av_strcasecmp(cmd, "next; - } - } - } else { - ffserver_parse_config_global(config, cmd, &p); - } - } - if (stream || feed || redirect) - ERROR("Missing closing tag\n", - stream ? "Stream" : (feed ? "Feed" : "Redirect")); - - fclose(f); - if (ret < 0) - return ret; - if (config->errors) - return AVERROR(EINVAL); - else - return 0; -} - -#undef ERROR -#undef WARNING - -void ffserver_free_child_args(void *argsp) -{ - int i; - char **args; - if (!argsp) - return; - args = *(char ***)argsp; - if (!args) - return; - for (i = 0; i < MAX_CHILD_ARGS; i++) - av_free(args[i]); - av_freep(argsp); -} diff --git a/fftools/ffserver_config.h b/fftools/ffserver_config.h deleted file mode 100644 index 089b8484d..000000000 --- a/fftools/ffserver_config.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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 FFTOOLS_FFSERVER_CONFIG_H -#define FFTOOLS_FFSERVER_CONFIG_H - -#define FFM_PACKET_SIZE 4096 - -#include "libavutil/dict.h" -#include "libavformat/avformat.h" -#include "libavformat/network.h" - -#define FFSERVER_MAX_STREAMS 20 - -/* each generated stream is described here */ -enum FFServerStreamType { - STREAM_TYPE_LIVE, - STREAM_TYPE_STATUS, - STREAM_TYPE_REDIRECT, -}; - -enum FFServerIPAddressAction { - IP_ALLOW = 1, - IP_DENY, -}; - -typedef struct FFServerIPAddressACL { - struct FFServerIPAddressACL *next; - enum FFServerIPAddressAction action; - /* These are in host order */ - struct in_addr first; - struct in_addr last; -} FFServerIPAddressACL; - -/** - * This holds the stream parameters for an AVStream, it cannot be a AVStream - * because AVStreams cannot be instanciated without a AVFormatContext, especially - * not outside libavformat. - * - * The fields of this struct have the same semantics as the fields of an AVStream. - */ -typedef struct LayeredAVStream { - int index; - int id; - AVCodecParameters *codecpar; - AVCodecContext *codec; - AVRational time_base; - int pts_wrap_bits; - AVRational sample_aspect_ratio; - char *recommended_encoder_configuration; -} LayeredAVStream; - -/* description of each stream of the ffserver.conf file */ -typedef struct FFServerStream { - enum FFServerStreamType stream_type; - char filename[1024]; /* stream filename */ - struct FFServerStream *feed; /* feed we are using (can be null if coming from file) */ - AVDictionary *in_opts; /* input parameters */ - AVDictionary *metadata; /* metadata to set on the stream */ - AVInputFormat *ifmt; /* if non NULL, force input format */ - AVOutputFormat *fmt; - FFServerIPAddressACL *acl; - char dynamic_acl[1024]; - int nb_streams; - int prebuffer; /* Number of milliseconds early to start */ - int64_t max_time; /* Number of milliseconds to run */ - int send_on_key; - LayeredAVStream *streams[FFSERVER_MAX_STREAMS]; - int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ - char feed_filename[1024]; /* file name of the feed storage, or - input file name for a stream */ - pid_t pid; /* Of ffmpeg process */ - time_t pid_start; /* Of ffmpeg process */ - char **child_argv; - struct FFServerStream *next; - unsigned bandwidth; /* bandwidth, in kbits/s */ - /* RTSP options */ - char *rtsp_option; - /* multicast specific */ - int is_multicast; - struct in_addr multicast_ip; - int multicast_port; /* first port used for multicast */ - int multicast_ttl; - int loop; /* if true, send the stream in loops (only meaningful if file) */ - char single_frame; /* only single frame */ - - /* feed specific */ - int feed_opened; /* true if someone is writing to the feed */ - int is_feed; /* true if it is a feed */ - int readonly; /* True if writing is prohibited to the file */ - int truncate; /* True if feeder connection truncate the feed file */ - int conns_served; - int64_t bytes_served; - int64_t feed_max_size; /* maximum storage size, zero means unlimited */ - int64_t feed_write_index; /* current write position in feed (it wraps around) */ - int64_t feed_size; /* current size of feed */ - struct FFServerStream *next_feed; -} FFServerStream; - -typedef struct FFServerConfig { - char *filename; - FFServerStream *first_feed; /* contains only feeds */ - FFServerStream *first_stream; /* contains all streams, including feeds */ - unsigned int nb_max_http_connections; - unsigned int nb_max_connections; - uint64_t max_bandwidth; - int debug; - int bitexact; - char logfilename[1024]; - struct sockaddr_in http_addr; - struct sockaddr_in rtsp_addr; - int errors; - int warnings; - int use_defaults; - // Following variables MUST NOT be used outside configuration parsing code. - enum AVCodecID guessed_audio_codec_id; - enum AVCodecID guessed_video_codec_id; - AVDictionary *video_opts; /* AVOptions for video encoder */ - AVDictionary *audio_opts; /* AVOptions for audio encoder */ - AVCodecContext *dummy_actx; /* Used internally to test audio AVOptions. */ - AVCodecContext *dummy_vctx; /* Used internally to test video AVOptions. */ - int no_audio; - int no_video; - int line_num; - int stream_use_defaults; -} FFServerConfig; - -void ffserver_get_arg(char *buf, int buf_size, const char **pp); - -void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed, - FFServerIPAddressACL *ext_acl, - const char *p, const char *filename, int line_num); - -int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config); - -void ffserver_free_child_args(void *argsp); - -#endif /* FFTOOLS_FFSERVER_CONFIG_H */ diff --git a/libavcodec/.gitignore b/libavcodec/.gitignore new file mode 100644 index 000000000..77a2ab1bd --- /dev/null +++ b/libavcodec/.gitignore @@ -0,0 +1,4 @@ +/*_tablegen +/*_tables.c +/*_tables.h +/bsf_list.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index c4ec09b1c..cfacd6b70 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1,7 +1,9 @@ NAME = avcodec DESC = FFmpeg codec library -HEADERS = avcodec.h \ +HEADERS = ac3_parser.h \ + adts_parser.h \ + avcodec.h \ avdct.h \ avfft.h \ d3d11va.h \ @@ -12,15 +14,15 @@ HEADERS = avcodec.h \ mediacodec.h \ qsv.h \ vaapi.h \ - vda.h \ vdpau.h \ version.h \ videotoolbox.h \ vorbis_parser.h \ xvmc.h \ -OBJS = allcodecs.o \ - audioconvert.o \ +OBJS = ac3_parser.o \ + adts_parser.o \ + allcodecs.o \ avdct.o \ avpacket.o \ avpicture.o \ @@ -45,8 +47,6 @@ OBJS = allcodecs.o \ profiles.o \ qsv_api.o \ raw.o \ - resample.o \ - resample2.o \ utils.o \ vorbis_parser.o \ xiph.o \ @@ -54,11 +54,17 @@ OBJS = allcodecs.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_H264) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o @@ -91,7 +97,6 @@ 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_LIBXVID) += libxvid_rc.o OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o @@ -146,10 +151,10 @@ 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 \ - aacadtsdec.o mpeg4audio.o kbdwin.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 \ - aacadtsdec.o mpeg4audio.o kbdwin.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 \ @@ -183,6 +188,8 @@ OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpegenc_common.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_APNG_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o @@ -331,18 +338,18 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_mb.o h264_picture.o \ h264_refs.o h264_sei.o \ h264_slice.o h264data.o -OBJS-$(CONFIG_H264_CUVID_DECODER) += cuvid.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_VDA_DECODER) += vda_h264_dec.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 vaapi_encode_h26x.o +OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.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 @@ -351,7 +358,8 @@ OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.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_CUVID_DECODER) += cuvid.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 @@ -359,7 +367,7 @@ 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 vaapi_encode_h26x.o +OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.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 @@ -396,6 +404,7 @@ 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 @@ -405,6 +414,7 @@ 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_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 @@ -616,7 +626,7 @@ 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) += cuvid.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 @@ -635,7 +645,7 @@ 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) += cuvid.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 @@ -645,7 +655,7 @@ 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) += cuvid.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 @@ -822,8 +832,8 @@ 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_VDA) += vda.o videotoolbox.o OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o OBJS-$(CONFIG_VDPAU) += vdpau.o @@ -831,36 +841,44 @@ 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_VDA_HWACCEL) += vda_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_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 @@ -880,7 +898,6 @@ 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_DEMUXER) += aacadtsdec.o mpeg4audio.o OBJS-$(CONFIG_SPDIF_MUXER) += dca.o OBJS-$(CONFIG_TAK_DEMUXER) += tak.o OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o @@ -951,15 +968,14 @@ 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_LIBXVID_ENCODER) += libxvid.o +OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o libxvid_rc.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 \ - aacadtsdec.o mpeg4audio.o -OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.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_BMP_PARSER) += bmp_parser.o OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o @@ -989,7 +1005,8 @@ 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 vorbis_data.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 @@ -1004,14 +1021,16 @@ 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 aacadtsdec.o \ - mpeg4audio.o +OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o mpeg4audio.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_EXTRACT_EXTRADATA_BSF) += extract_extradata_bsf.o \ h2645_parse.o +OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o +OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o +OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.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 @@ -1020,10 +1039,12 @@ 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_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_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 @@ -1048,6 +1069,7 @@ SKIPHEADERS += %_tablegen.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 @@ -1060,9 +1082,8 @@ 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_VDA) += vda.h vda_vt_internal.h SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h -SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vda_vt_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 \ @@ -1082,6 +1103,7 @@ TESTPROGS-$(CONFIG_GOLOMB) += golomb TESTPROGS-$(CONFIG_IDCTDSP) += dct TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter TESTPROGS-$(HAVE_MMX) += motion +TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate TESTPROGS-$(CONFIG_RANGECODER) += rangecoder TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c index c9ba6bf06..4e834b442 100644 --- a/libavcodec/aac_ac3_parser.c +++ b/libavcodec/aac_ac3_parser.c @@ -86,20 +86,8 @@ get_next: the frame). */ if (avctx->codec_id != AV_CODEC_ID_AAC) { avctx->sample_rate = s->sample_rate; - - /* (E-)AC-3: allow downmixing to stereo or mono */ - if (s->channels > 1 && - avctx->request_channel_layout == AV_CH_LAYOUT_MONO) { - avctx->channels = 1; - avctx->channel_layout = AV_CH_LAYOUT_MONO; - } else if (s->channels > 2 && - avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) { - avctx->channels = 2; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else { - avctx->channels = s->channels; - avctx->channel_layout = s->channel_layout; - } + avctx->channels = s->channels; + avctx->channel_layout = s->channel_layout; s1->duration = s->samples; avctx->audio_service_type = s->service_type; } diff --git a/libavcodec/aac_adtstoasc_bsf.c b/libavcodec/aac_adtstoasc_bsf.c index 4bcf55b19..49f1f095e 100644 --- a/libavcodec/aac_adtstoasc_bsf.c +++ b/libavcodec/aac_adtstoasc_bsf.c @@ -19,8 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "adts_header.h" +#include "adts_parser.h" #include "avcodec.h" -#include "aacadtsdec.h" #include "bsf.h" #include "put_bits.h" #include "get_bits.h" @@ -52,12 +53,12 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) if (bsfc->par_in->extradata && in->size >= 2 && (AV_RB16(in->data) >> 4) != 0xfff) goto finish; - if (in->size < AAC_ADTS_HEADER_SIZE) + if (in->size < AV_AAC_ADTS_HEADER_SIZE) goto packet_too_small; - init_get_bits(&gb, in->data, AAC_ADTS_HEADER_SIZE * 8); + init_get_bits(&gb, in->data, AV_AAC_ADTS_HEADER_SIZE * 8); - if (avpriv_aac_parse_header(&gb, &hdr) < 0) { + 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; @@ -70,10 +71,10 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) goto fail; } - in->size -= AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + in->size -= AV_AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; if (in->size <= 0) goto packet_too_small; - in->data += AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + in->data += AV_AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; if (!ctx->first_frame_done) { int pce_size = 0; @@ -91,7 +92,7 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) goto fail; } init_put_bits(&pb, pce_data, MAX_PCE_SIZE); - pce_size = avpriv_copy_pce_data(&pb, &gb)/8; + pce_size = ff_copy_pce_data(&pb, &gb) / 8; flush_put_bits(&pb); in->size -= get_bits_count(&gb)/8; in->data += get_bits_count(&gb)/8; diff --git a/libavcodec/aac_parser.c b/libavcodec/aac_parser.c index 0b868edcb..b8692625f 100644 --- a/libavcodec/aac_parser.c +++ b/libavcodec/aac_parser.c @@ -22,7 +22,8 @@ #include "parser.h" #include "aac_ac3_parser.h" -#include "aacadtsdec.h" +#include "adts_header.h" +#include "adts_parser.h" #include "get_bits.h" #include "mpeg4audio.h" @@ -38,9 +39,10 @@ static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info, } tmp; tmp.u64 = av_be2ne64(state); - init_get_bits(&bits, tmp.u8+8-AAC_ADTS_HEADER_SIZE, AAC_ADTS_HEADER_SIZE * 8); + init_get_bits(&bits, tmp.u8 + 8 - AV_AAC_ADTS_HEADER_SIZE, + AV_AAC_ADTS_HEADER_SIZE * 8); - if ((size = avpriv_aac_parse_header(&bits, &hdr)) < 0) + if ((size = ff_adts_header_parse(&bits, &hdr)) < 0) return 0; *need_next_header = 0; *new_frame_start = 1; @@ -54,7 +56,7 @@ static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info, static av_cold int aac_parse_init(AVCodecParserContext *s1) { AACAC3ParseContext *s = s1->priv_data; - s->header_size = AAC_ADTS_HEADER_SIZE; + s->header_size = AV_AAC_ADTS_HEADER_SIZE; s->sync = aac_sync; return 0; } diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index fe5087147..44352764a 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -50,11 +50,11 @@ #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 "aacadtsdec.h" #include "profiles.h" #include "libavutil/intfloat.h" diff --git a/libavcodec/aacdec_fixed.c b/libavcodec/aacdec_fixed.c index f6a533010..f96999efb 100644 --- a/libavcodec/aacdec_fixed.c +++ b/libavcodec/aacdec_fixed.c @@ -75,11 +75,11 @@ #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 "aacadtsdec.h" #include "profiles.h" #include "libavutil/intfloat.h" @@ -307,9 +307,9 @@ static av_always_inline void predict(PredictorState *ps, int *coef, if (shift < 31) { if (shift > 0) { - *coef += (pv.mant + (1 << (shift - 1))) >> shift; + *coef += (unsigned)((pv.mant + (1 << (shift - 1))) >> shift); } else - *coef += pv.mant << -shift; + *coef += (unsigned)pv.mant << -shift; } } @@ -394,7 +394,7 @@ static void apply_dependent_coupling_fixed(AACContext *ac, 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 * (1 << shift); + dest[group * 128 + k] += tmp * (1U << shift); } } } diff --git a/libavcodec/aacdec_template.c b/libavcodec/aacdec_template.c index 082cc908d..6c6cdd84a 100644 --- a/libavcodec/aacdec_template.c +++ b/libavcodec/aacdec_template.c @@ -2955,7 +2955,7 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb) uint8_t layout_map[MAX_ELEM_ID*4][3]; int layout_map_tags, ret; - size = avpriv_aac_parse_header(gb, &hdr_info); + 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. diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 11da26074..6d94c7690 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -50,17 +50,59 @@ 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 void put_audio_specific_config(AVCodecContext *avctx) +static int put_audio_specific_config(AVCodecContext *avctx) { PutBitContext pb; AACEncContext *s = avctx->priv_data; - int channels = s->channels - (s->channels == 8 ? 1 : 0); + int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0)); + const int max_size = 32; - init_put_bits(&pb, avctx->extradata, avctx->extradata_size); + 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); @@ -68,12 +110,17 @@ static void put_audio_specific_config(AVCodecContext *avctx) 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) @@ -488,7 +535,7 @@ 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 = aac_chan_maps[s->channels - 1]; + const uint8_t *channel_map = s->reorder_map; /* copy and remap input samples */ for (ch = 0; ch < s->channels; ch++) { @@ -895,7 +942,6 @@ 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); - FF_ALLOCZ_OR_GOTO(avctx, avctx->extradata, 5 + AV_INPUT_BUFFER_PADDING_SIZE, alloc_fail); for(ch = 0; ch < s->channels; ch++) s->planar_samples[ch] = s->buffer.samples + 3 * 1024 * ch; @@ -920,16 +966,35 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) /* Constants */ s->last_frame_pb_count = 0; - avctx->extradata_size = 5; 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; - ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7, - "Unsupported number of channels: %d\n", s->channels); - s->chan_map = aac_chan_configs[s->channels-1]; + + 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) { + for (i = 0; i < FF_ARRAY_ELEMS(aac_pce_configs); i++) + if (avctx->channel_layout == aac_pce_configs[i].layout) + break; + ERROR_IF(i == FF_ARRAY_ELEMS(aac_pce_configs), "Unsupported channel layout\n"); + av_log(avctx, AV_LOG_INFO, "Using a PCE to encode channel layout\n"); + 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 */ @@ -1015,7 +1080,8 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) if ((ret = alloc_buffers(avctx, s)) < 0) goto fail; - put_audio_specific_config(avctx); + 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]; @@ -1052,24 +1118,25 @@ fail: #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_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "coder"}, + {"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", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, 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 = { - "AAC encoder", - av_default_item_name, - aacenc_options, - LIBAVUTIL_VERSION_INT, + .class_name = "AAC encoder", + .item_name = av_default_item_name, + .option = aacenc_options, + .version = LIBAVUTIL_VERSION_INT, }; static const AVCodecDefault aac_encode_defaults[] = { diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index ea2d3b962..5a015ca92 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -45,6 +45,7 @@ typedef struct AACEncOptions { int pns; int tns; int ltp; + int pce; int pred; int mid_side; int intensity_stereo; @@ -89,6 +90,286 @@ typedef struct AACQuantizeBandCostCacheEntry { 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 */ @@ -99,12 +380,15 @@ typedef struct AACEncContext { FFTContext mdct1024; ///< long (1024 samples) frame transform context FFTContext mdct128; ///< short (128 samples) frame transform context AVFloatDSPContext *fdsp; - float *planar_samples[8]; ///< saved preprocessed input + 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 diff --git a/libavcodec/aacenctab.h b/libavcodec/aacenctab.h index 5fc941123..64932d709 100644 --- a/libavcodec/aacenctab.h +++ b/libavcodec/aacenctab.h @@ -36,13 +36,24 @@ /** Total number of codebooks, including special ones **/ #define CB_TOT_ALL 15 -#define AAC_MAX_CHANNELS 8 +#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 diff --git a/libavcodec/aacpsdsp_template.c b/libavcodec/aacpsdsp_template.c index e35e9699b..19be20065 100644 --- a/libavcodec/aacpsdsp_template.c +++ b/libavcodec/aacpsdsp_template.c @@ -130,12 +130,12 @@ static void ps_decorrelate_c(INTFLOAT (*out)[2], INTFLOAT (*delay)[2], INTFLOAT apd_im = in_im; in_re = AAC_MSUB30(link_delay_re, fractional_delay_re, link_delay_im, fractional_delay_im); - in_re -= a_re; + in_re -= (UINTFLOAT)a_re; in_im = AAC_MADD30(link_delay_re, fractional_delay_im, link_delay_im, fractional_delay_re); - in_im -= a_im; - ap_delay[m][n+5][0] = apd_re + AAC_MUL31(ag[m], in_re); - ap_delay[m][n+5][1] = apd_im + AAC_MUL31(ag[m], in_im); + 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); diff --git a/libavcodec/aacsbr_fixed.c b/libavcodec/aacsbr_fixed.c index 289bb86a8..3d5875a46 100644 --- a/libavcodec/aacsbr_fixed.c +++ b/libavcodec/aacsbr_fixed.c @@ -433,6 +433,7 @@ static void sbr_gain_calc(AACContext *ac, SpectralBandReplication *sbr, 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]); diff --git a/libavcodec/aarch64/mpegaudiodsp_neon.S b/libavcodec/aarch64/mpegaudiodsp_neon.S index cc7d9b321..b6ef13122 100644 --- a/libavcodec/aarch64/mpegaudiodsp_neon.S +++ b/libavcodec/aarch64/mpegaudiodsp_neon.S @@ -24,7 +24,7 @@ #define WFRAC_BITS 16 // fractional bits for window #define OUT_SHIFT (WFRAC_BITS + FRAC_BITS - 15) -const tbl_rev128.s, align=4 +const tbl_rev128_s, align=4 .byte 12, 13, 14, 15 .byte 8, 9, 10, 11 .byte 4, 5, 6, 7 @@ -39,7 +39,7 @@ function ff_mpadsp_apply_window_\type\()_neon, export=1 ld1 {v4.4s,v5.4s,v6.4s,v7.4s}, [x7], #64 st1 {v0.4s,v1.4s,v2.4s,v3.4s}, [x8], #64 st1 {v4.4s,v5.4s,v6.4s,v7.4s}, [x8], #64 - movrel x15, tbl_rev128.s + movrel x15, tbl_rev128_s ld1 {v27.4s}, [x15] .ifc \type, fixed lsl x4, x4, #1 diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c index 83dd90ff6..1015245a9 100644 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@ -20,15 +20,19 @@ * 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 @@ -47,16 +51,9 @@ static const uint8_t center_levels[4] = { 4, 5, 6, 5 }; static const uint8_t surround_levels[4] = { 4, 6, 7, 6 }; -int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **phdr) +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) { int frame_size_code; - AC3HeaderInfo *hdr; - - if (!*phdr) - *phdr = av_mallocz(sizeof(AC3HeaderInfo)); - if (!*phdr) - return AVERROR(ENOMEM); - hdr = *phdr; memset(hdr, 0, sizeof(*hdr)); @@ -151,6 +148,46 @@ int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **phdr) 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; + + init_get_bits8(&gb, buf, size); + 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) { @@ -159,11 +196,11 @@ static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, uint64_t u64; uint8_t u8[8 + AV_INPUT_BUFFER_PADDING_SIZE]; } tmp = { av_be2ne64(state) }; - AC3HeaderInfo hdr, *phdr = &hdr; + AC3HeaderInfo hdr; GetBitContext gbc; init_get_bits(&gbc, tmp.u8+8-AC3_HEADER_SIZE, 54); - err = avpriv_ac3_parse_header(&gbc, &phdr); + err = ff_ac3_parse_header(&gbc, &hdr); if(err < 0) return 0; @@ -202,3 +239,18 @@ AVCodecParser ff_ac3_parser = { .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/libavcodec/ac3_parser.h b/libavcodec/ac3_parser.h index dc5d035e1..ff8cc4cf0 100644 --- a/libavcodec/ac3_parser.h +++ b/libavcodec/ac3_parser.h @@ -23,20 +23,14 @@ #ifndef AVCODEC_AC3_PARSER_H #define AVCODEC_AC3_PARSER_H -#include "ac3.h" -#include "get_bits.h" +#include +#include /** - * 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 Pointer to struct where header info is written. - * will be allocated if NULL - * @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. + * Extract the bitstream ID and the frame size from AC-3 data. */ -int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **hdr); +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/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h new file mode 100644 index 000000000..3648802a7 --- /dev/null +++ b/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/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index c393076ae..244a18323 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -36,7 +36,7 @@ #include "bswapdsp.h" #include "internal.h" #include "aac_ac3_parser.h" -#include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "kbdwin.h" @@ -297,10 +297,10 @@ static int ac3_parse_header(AC3DecodeContext *s) */ static int parse_frame_header(AC3DecodeContext *s) { - AC3HeaderInfo hdr, *phdr=&hdr; + AC3HeaderInfo hdr; int err; - err = avpriv_ac3_parse_header(&s->gbc, &phdr); + err = ff_ac3_parse_header(&s->gbc, &hdr); if (err) return err; diff --git a/libavcodec/ac3tab.h b/libavcodec/ac3tab.h index f529fc807..ade6fb15e 100644 --- a/libavcodec/ac3tab.h +++ b/libavcodec/ac3tab.h @@ -26,10 +26,11 @@ #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 const uint16_t avpriv_ac3_channel_layout_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]; diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index be206c55b..cd3bbd33c 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1115,6 +1115,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, int16_t *out1 = samples_p[1]; int samples_per_block = 28 * (3 - avctx->channels) * 4; int sample_offset = 0; + int bytes_remaining; while (bytestream2_get_bytes_left(&gb) >= 128) { if ((ret = xa_decode(avctx, out0, out1, buf + bytestream2_tell(&gb), &c->status[0], &c->status[1], @@ -1123,6 +1124,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, bytestream2_skipu(&gb, 128); sample_offset += samples_per_block; } + /* Less than a full block of data left, e.g. when reading from + * 2324 byte per sector XA; the remainder is padding */ + bytes_remaining = bytestream2_get_bytes_left(&gb); + if (bytes_remaining > 0) { + bytestream2_skip(&gb, bytes_remaining); + } break; } case AV_CODEC_ID_ADPCM_IMA_EA_EACS: diff --git a/libavcodec/aacadtsdec.c b/libavcodec/adts_header.c similarity index 93% rename from libavcodec/aacadtsdec.c rename to libavcodec/adts_header.c index d0814ac27..0889820f8 100644 --- a/libavcodec/aacadtsdec.c +++ b/libavcodec/adts_header.c @@ -22,11 +22,12 @@ */ #include "aac_ac3_parser.h" -#include "aacadtsdec.h" +#include "adts_header.h" +#include "adts_parser.h" #include "get_bits.h" #include "mpeg4audio.h" -int avpriv_aac_parse_header(GetBitContext *gbc, AACADTSHeaderInfo *hdr) +int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) { int size, rdb, ch, sr; int aot, crc_abs; @@ -51,7 +52,7 @@ int avpriv_aac_parse_header(GetBitContext *gbc, AACADTSHeaderInfo *hdr) skip_bits1(gbc); /* copyright_identification_bit */ skip_bits1(gbc); /* copyright_identification_start */ size = get_bits(gbc, 13); /* aac_frame_length */ - if (size < AAC_ADTS_HEADER_SIZE) + if (size < AV_AAC_ADTS_HEADER_SIZE) return AAC_AC3_PARSE_ERROR_FRAME_SIZE; skip_bits(gbc, 11); /* adts_buffer_fullness */ diff --git a/libavcodec/aacadtsdec.h b/libavcodec/adts_header.h similarity index 86% rename from libavcodec/aacadtsdec.h rename to libavcodec/adts_header.h index d0584ef36..f615f6a9f 100644 --- a/libavcodec/aacadtsdec.h +++ b/libavcodec/adts_header.h @@ -20,14 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_AACADTSDEC_H -#define AVCODEC_AACADTSDEC_H +#ifndef AVCODEC_ADTS_HEADER_H +#define AVCODEC_ADTS_HEADER_H -#include #include "get_bits.h" -#define AAC_ADTS_HEADER_SIZE 7 - typedef struct AACADTSHeaderInfo { uint32_t sample_rate; uint32_t samples; @@ -40,7 +37,6 @@ typedef struct AACADTSHeaderInfo { } AACADTSHeaderInfo; /** - * Parse AAC frame header. * 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. @@ -49,6 +45,6 @@ typedef struct AACADTSHeaderInfo { * -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 avpriv_aac_parse_header(GetBitContext *gbc, AACADTSHeaderInfo *hdr); +int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr); -#endif /* AVCODEC_AACADTSDEC_H */ +#endif /* AVCODEC_ADTS_HEADER_H */ diff --git a/libavfilter/unsharp_opencl.h b/libavcodec/adts_parser.c similarity index 59% rename from libavfilter/unsharp_opencl.h rename to libavcodec/adts_parser.c index 3aefab62e..5c9f8ff6f 100644 --- a/libavfilter/unsharp_opencl.h +++ b/libavcodec/adts_parser.c @@ -1,6 +1,4 @@ /* - * Copyright (C) 2013 Wei Gao - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -18,17 +16,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_UNSHARP_OPENCL_H -#define AVFILTER_UNSHARP_OPENCL_H +#include "config.h" -#include "unsharp.h" +#include +#include -int ff_opencl_unsharp_init(AVFilterContext *ctx); +#include "adts_header.h" +#include "adts_parser.h" -void ff_opencl_unsharp_uninit(AVFilterContext *ctx); - -int ff_opencl_unsharp_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - -int ff_opencl_apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - -#endif /* AVFILTER_UNSHARP_OPENCL_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/compat/tms470/math.h b/libavcodec/adts_parser.h similarity index 56% rename from compat/tms470/math.h rename to libavcodec/adts_parser.h index 0a42743a0..f85becd13 100644 --- a/compat/tms470/math.h +++ b/libavcodec/adts_parser.h @@ -16,15 +16,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef COMPAT_TMS470_MATH_H -#define COMPAT_TMS470_MATH_H +#ifndef AVCODEC_ADTS_PARSER_H +#define AVCODEC_ADTS_PARSER_H -#include_next +#include +#include -#undef INFINITY -#undef NAN +#define AV_AAC_ADTS_HEADER_SIZE 7 -#define INFINITY (*(const float*)((const unsigned []){ 0x7f800000 })) -#define NAN (*(const float*)((const unsigned []){ 0x7fc00000 })) +/** + * 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 /* COMPAT_TMS470_MATH_H */ +#endif /* AVCODEC_ADTS_PARSER_H */ diff --git a/libavcodec/alac.c b/libavcodec/alac.c index d6bd21ba1..93cf198ee 100644 --- a/libavcodec/alac.c +++ b/libavcodec/alac.c @@ -524,7 +524,7 @@ static int alac_set_info(ALACContext *alac) alac->max_samples_per_frame = bytestream2_get_be32u(&gb); if (!alac->max_samples_per_frame || - alac->max_samples_per_frame > INT_MAX / sizeof(int32_t)) { + alac->max_samples_per_frame > 4096 * 4096) { av_log(alac->avctx, AV_LOG_ERROR, "max samples per frame invalid: %"PRIu32"\n", alac->max_samples_per_frame); diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 4f34312e6..ed1e7ab06 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -29,13 +29,6 @@ #include "avcodec.h" #include "version.h" -#define REGISTER_HWACCEL(X, x) \ - { \ - extern AVHWAccel ff_##x##_hwaccel; \ - if (CONFIG_##X##_HWACCEL) \ - av_register_hwaccel(&ff_##x##_hwaccel); \ - } - #define REGISTER_ENCODER(X, x) \ { \ extern AVCodec ff_##x##_encoder; \ @@ -61,75 +54,6 @@ static void register_all(void) { - /* hardware accelerators */ - REGISTER_HWACCEL(H263_VAAPI, h263_vaapi); - REGISTER_HWACCEL(H263_VIDEOTOOLBOX, h263_videotoolbox); - REGISTER_HWACCEL(H264_CUVID, h264_cuvid); - REGISTER_HWACCEL(H264_D3D11VA, h264_d3d11va); - REGISTER_HWACCEL(H264_D3D11VA2, h264_d3d11va2); - REGISTER_HWACCEL(H264_DXVA2, h264_dxva2); - REGISTER_HWACCEL(H264_MEDIACODEC, h264_mediacodec); - REGISTER_HWACCEL(H264_MMAL, h264_mmal); - REGISTER_HWACCEL(H264_QSV, h264_qsv); - REGISTER_HWACCEL(H264_VAAPI, h264_vaapi); - REGISTER_HWACCEL(H264_VDA, h264_vda); - REGISTER_HWACCEL(H264_VDA_OLD, h264_vda_old); - REGISTER_HWACCEL(H264_VDPAU, h264_vdpau); - REGISTER_HWACCEL(H264_VIDEOTOOLBOX, h264_videotoolbox); - REGISTER_HWACCEL(HEVC_CUVID, hevc_cuvid); - REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va); - REGISTER_HWACCEL(HEVC_D3D11VA2, hevc_d3d11va2); - REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2); - REGISTER_HWACCEL(HEVC_MEDIACODEC, hevc_mediacodec); - REGISTER_HWACCEL(HEVC_QSV, hevc_qsv); - REGISTER_HWACCEL(HEVC_VAAPI, hevc_vaapi); - REGISTER_HWACCEL(HEVC_VDPAU, hevc_vdpau); - REGISTER_HWACCEL(HEVC_VIDEOTOOLBOX, hevc_videotoolbox); - REGISTER_HWACCEL(MJPEG_CUVID, mjpeg_cuvid); - REGISTER_HWACCEL(MPEG1_CUVID, mpeg1_cuvid); - REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc); - REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau); - REGISTER_HWACCEL(MPEG1_VIDEOTOOLBOX, mpeg1_videotoolbox); - REGISTER_HWACCEL(MPEG2_CUVID, mpeg2_cuvid); - REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc); - REGISTER_HWACCEL(MPEG2_D3D11VA, mpeg2_d3d11va); - REGISTER_HWACCEL(MPEG2_D3D11VA2, mpeg2_d3d11va2); - REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2); - REGISTER_HWACCEL(MPEG2_MMAL, mpeg2_mmal); - REGISTER_HWACCEL(MPEG2_QSV, mpeg2_qsv); - REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi); - REGISTER_HWACCEL(MPEG2_VDPAU, mpeg2_vdpau); - REGISTER_HWACCEL(MPEG2_VIDEOTOOLBOX, mpeg2_videotoolbox); - REGISTER_HWACCEL(MPEG2_MEDIACODEC, mpeg2_mediacodec); - REGISTER_HWACCEL(MPEG4_CUVID, mpeg4_cuvid); - REGISTER_HWACCEL(MPEG4_MEDIACODEC, mpeg4_mediacodec); - REGISTER_HWACCEL(MPEG4_MMAL, mpeg4_mmal); - REGISTER_HWACCEL(MPEG4_VAAPI, mpeg4_vaapi); - REGISTER_HWACCEL(MPEG4_VDPAU, mpeg4_vdpau); - REGISTER_HWACCEL(MPEG4_VIDEOTOOLBOX, mpeg4_videotoolbox); - REGISTER_HWACCEL(VC1_CUVID, vc1_cuvid); - REGISTER_HWACCEL(VC1_D3D11VA, vc1_d3d11va); - REGISTER_HWACCEL(VC1_D3D11VA2, vc1_d3d11va2); - REGISTER_HWACCEL(VC1_DXVA2, vc1_dxva2); - REGISTER_HWACCEL(VC1_VAAPI, vc1_vaapi); - REGISTER_HWACCEL(VC1_VDPAU, vc1_vdpau); - REGISTER_HWACCEL(VC1_MMAL, vc1_mmal); - REGISTER_HWACCEL(VC1_QSV, vc1_qsv); - REGISTER_HWACCEL(VP8_CUVID, vp8_cuvid); - REGISTER_HWACCEL(VP8_MEDIACODEC, vp8_mediacodec); - REGISTER_HWACCEL(VP8_QSV, vp8_qsv); - REGISTER_HWACCEL(VP9_CUVID, vp9_cuvid); - REGISTER_HWACCEL(VP9_D3D11VA, vp9_d3d11va); - REGISTER_HWACCEL(VP9_D3D11VA2, vp9_d3d11va2); - REGISTER_HWACCEL(VP9_DXVA2, vp9_dxva2); - REGISTER_HWACCEL(VP9_MEDIACODEC, vp9_mediacodec); - REGISTER_HWACCEL(VP9_VAAPI, vp9_vaapi); - REGISTER_HWACCEL(WMV3_D3D11VA, wmv3_d3d11va); - REGISTER_HWACCEL(WMV3_D3D11VA2, wmv3_d3d11va2); - REGISTER_HWACCEL(WMV3_DXVA2, wmv3_dxva2); - REGISTER_HWACCEL(WMV3_VAAPI, wmv3_vaapi); - REGISTER_HWACCEL(WMV3_VDPAU, wmv3_vdpau); - /* video codecs */ REGISTER_ENCODER(A64MULTI, a64multi); REGISTER_ENCODER(A64MULTI5, a64multi5); @@ -217,10 +141,6 @@ static void register_all(void) REGISTER_DECODER(H264_MMAL, h264_mmal); REGISTER_DECODER(H264_QSV, h264_qsv); REGISTER_DECODER(H264_RKMPP, h264_rkmpp); - REGISTER_DECODER(H264_VDA, h264_vda); -#if FF_API_VDPAU - REGISTER_DECODER(H264_VDPAU, h264_vdpau); -#endif REGISTER_ENCDEC (HAP, hap); REGISTER_DECODER(HEVC, hevc); REGISTER_DECODER(HEVC_QSV, hevc_qsv); @@ -246,30 +166,20 @@ static void register_all(void) REGISTER_ENCODER(LJPEG, ljpeg); REGISTER_DECODER(LOCO, loco); REGISTER_DECODER(M101, m101); - REGISTER_DECODER(MAGICYUV, magicyuv); + REGISTER_ENCDEC (MAGICYUV, magicyuv); REGISTER_DECODER(MDEC, mdec); REGISTER_DECODER(MIMIC, mimic); REGISTER_ENCDEC (MJPEG, mjpeg); REGISTER_DECODER(MJPEGB, mjpegb); REGISTER_DECODER(MMVIDEO, mmvideo); REGISTER_DECODER(MOTIONPIXELS, motionpixels); -#if FF_API_XVMC - REGISTER_DECODER(MPEG_XVMC, mpeg_xvmc); -#endif /* FF_API_XVMC */ REGISTER_ENCDEC (MPEG1VIDEO, mpeg1video); REGISTER_ENCDEC (MPEG2VIDEO, mpeg2video); REGISTER_ENCDEC (MPEG4, mpeg4); REGISTER_DECODER(MPEG4_CRYSTALHD, mpeg4_crystalhd); REGISTER_DECODER(MPEG4_V4L2M2M, mpeg4_v4l2m2m); REGISTER_DECODER(MPEG4_MMAL, mpeg4_mmal); -#if FF_API_VDPAU - REGISTER_DECODER(MPEG4_VDPAU, mpeg4_vdpau); -#endif REGISTER_DECODER(MPEGVIDEO, mpegvideo); -#if FF_API_VDPAU - REGISTER_DECODER(MPEG_VDPAU, mpeg_vdpau); - REGISTER_DECODER(MPEG1_VDPAU, mpeg1_vdpau); -#endif REGISTER_DECODER(MPEG1_V4L2M2M, mpeg1_v4l2m2m); REGISTER_DECODER(MPEG2_MMAL, mpeg2_mmal); REGISTER_DECODER(MPEG2_CRYSTALHD, mpeg2_crystalhd); @@ -365,9 +275,6 @@ static void register_all(void) REGISTER_DECODER(VBLE, vble); REGISTER_DECODER(VC1, vc1); REGISTER_DECODER(VC1_CRYSTALHD, vc1_crystalhd); -#if FF_API_VDPAU - REGISTER_DECODER(VC1_VDPAU, vc1_vdpau); -#endif REGISTER_DECODER(VC1IMAGE, vc1image); REGISTER_DECODER(VC1_MMAL, vc1_mmal); REGISTER_DECODER(VC1_QSV, vc1_qsv); @@ -396,9 +303,6 @@ static void register_all(void) REGISTER_ENCDEC (WMV2, wmv2); REGISTER_DECODER(WMV3, wmv3); REGISTER_DECODER(WMV3_CRYSTALHD, wmv3_crystalhd); -#if FF_API_VDPAU - REGISTER_DECODER(WMV3_VDPAU, wmv3_vdpau); -#endif REGISTER_DECODER(WMV3IMAGE, wmv3image); REGISTER_DECODER(WNV1, wnv1); REGISTER_DECODER(XAN_WC3, xan_wc3); @@ -428,6 +332,7 @@ static void register_all(void) REGISTER_DECODER(AMRNB, amrnb); REGISTER_DECODER(AMRWB, amrwb); REGISTER_DECODER(APE, ape); + REGISTER_ENCDEC (APTX, aptx); REGISTER_DECODER(ATRAC1, atrac1); REGISTER_DECODER(ATRAC3, atrac3); REGISTER_DECODER(ATRAC3AL, atrac3al); @@ -671,6 +576,7 @@ static void register_all(void) * above is available */ REGISTER_ENCODER(H263_V4L2M2M, h263_v4l2m2m); REGISTER_ENCDEC (LIBOPENH264, libopenh264); + REGISTER_ENCODER(H264_AMF, h264_amf); REGISTER_DECODER(H264_CUVID, h264_cuvid); REGISTER_ENCODER(H264_NVENC, h264_nvenc); REGISTER_ENCODER(H264_OMX, h264_omx); @@ -683,14 +589,17 @@ static void register_all(void) REGISTER_ENCODER(NVENC_H264, nvenc_h264); REGISTER_ENCODER(NVENC_HEVC, nvenc_hevc); #endif + REGISTER_ENCODER(HEVC_AMF, hevc_amf); REGISTER_DECODER(HEVC_CUVID, hevc_cuvid); REGISTER_DECODER(HEVC_MEDIACODEC, hevc_mediacodec); REGISTER_ENCODER(HEVC_NVENC, hevc_nvenc); REGISTER_ENCODER(HEVC_QSV, hevc_qsv); REGISTER_ENCODER(HEVC_V4L2M2M, hevc_v4l2m2m); REGISTER_ENCODER(HEVC_VAAPI, hevc_vaapi); + REGISTER_ENCODER(HEVC_VIDEOTOOLBOX, hevc_videotoolbox); REGISTER_ENCODER(LIBKVAZAAR, libkvazaar); REGISTER_DECODER(MJPEG_CUVID, mjpeg_cuvid); + REGISTER_ENCODER(MJPEG_QSV, mjpeg_qsv); REGISTER_ENCODER(MJPEG_VAAPI, mjpeg_vaapi); REGISTER_DECODER(MPEG1_CUVID, mpeg1_cuvid); REGISTER_DECODER(MPEG2_CUVID, mpeg2_cuvid); diff --git a/libavcodec/alpha/asm.h b/libavcodec/alpha/asm.h index 827721e77..6d850cecc 100644 --- a/libavcodec/alpha/asm.h +++ b/libavcodec/alpha/asm.h @@ -146,39 +146,6 @@ struct unaligned_long { uint64_t l; } __attribute__((packed)); #define unpkbw(a) ({ uint64_t __r; __asm__ (".arch ev6; unpkbw %r1,%0" : "=r" (__r) : "rJ" (a)); __r; }) #endif -#elif defined(__DECC) /* Digital/Compaq/hp "ccc" compiler */ - -#include -#define ldq(p) (*(const uint64_t *) (p)) -#define ldl(p) (*(const int32_t *) (p)) -#define stq(l, p) do { *(uint64_t *) (p) = (l); } while (0) -#define stl(l, p) do { *(int32_t *) (p) = (l); } while (0) -#define ldq_u(a) asm ("ldq_u %v0,0(%a0)", a) -#define uldq(a) (*(const __unaligned uint64_t *) (a)) -#define cmpbge(a, b) asm ("cmpbge %a0,%a1,%v0", a, b) -#define extql(a, b) asm ("extql %a0,%a1,%v0", a, b) -#define extwl(a, b) asm ("extwl %a0,%a1,%v0", a, b) -#define extqh(a, b) asm ("extqh %a0,%a1,%v0", a, b) -#define zap(a, b) asm ("zap %a0,%a1,%v0", a, b) -#define zapnot(a, b) asm ("zapnot %a0,%a1,%v0", a, b) -#define amask(a) asm ("amask %a0,%v0", a) -#define implver() asm ("implver %v0") -#define rpcc() asm ("rpcc %v0") -#define minub8(a, b) asm ("minub8 %a0,%a1,%v0", a, b) -#define minsb8(a, b) asm ("minsb8 %a0,%a1,%v0", a, b) -#define minuw4(a, b) asm ("minuw4 %a0,%a1,%v0", a, b) -#define minsw4(a, b) asm ("minsw4 %a0,%a1,%v0", a, b) -#define maxub8(a, b) asm ("maxub8 %a0,%a1,%v0", a, b) -#define maxsb8(a, b) asm ("maxsb8 %a0,%a1,%v0", a, b) -#define maxuw4(a, b) asm ("maxuw4 %a0,%a1,%v0", a, b) -#define maxsw4(a, b) asm ("maxsw4 %a0,%a1,%v0", a, b) -#define perr(a, b) asm ("perr %a0,%a1,%v0", a, b) -#define pklb(a) asm ("pklb %a0,%v0", a) -#define pkwb(a) asm ("pkwb %a0,%v0", a) -#define unpkbl(a) asm ("unpkbl %a0,%v0", a) -#define unpkbw(a) asm ("unpkbw %a0,%v0", a) -#define wh64(a) asm ("wh64 %a0", a) - #else #error "Unknown compiler!" #endif diff --git a/libavcodec/alpha/idctdsp_alpha.c b/libavcodec/alpha/idctdsp_alpha.c index 1923ebbc5..bd4384253 100644 --- a/libavcodec/alpha/idctdsp_alpha.c +++ b/libavcodec/alpha/idctdsp_alpha.c @@ -118,8 +118,7 @@ av_cold void ff_idctdsp_init_alpha(IDCTDSPContext *c, AVCodecContext *avctx, add_pixels_clamped_axp_p = c->add_pixels_clamped; if (!high_bit_depth && !avctx->lowres && - (avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_SIMPLEALPHA)) { + (avctx->idct_algo == FF_IDCT_AUTO)) { c->idct_put = ff_simple_idct_put_axp; c->idct_add = ff_simple_idct_add_axp; c->idct = ff_simple_idct_axp; diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index 13bd52f29..ca8701e6d 100644 --- a/libavcodec/alsdec.c +++ b/libavcodec/alsdec.c @@ -704,11 +704,6 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) } else { *bd->opt_order = sconf->max_order; } - if (*bd->opt_order > bd->block_length) { - *bd->opt_order = bd->block_length; - av_log(avctx, AV_LOG_ERROR, "Predictor order too large.\n"); - return AVERROR_INVALIDDATA; - } opt_order = *bd->opt_order; if (opt_order) { @@ -925,7 +920,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) // reconstruct all samples from residuals if (bd->ra_block) { - for (smp = 0; smp < opt_order; smp++) { + for (smp = 0; smp < FFMIN(opt_order, block_length); smp++) { y = 1 << 19; for (sb = 0; sb < smp; sb++) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c new file mode 100644 index 000000000..f8b68070a --- /dev/null +++ b/libavcodec/amfenc.c @@ -0,0 +1,606 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/hwcontext.h" +#if CONFIG_D3D11VA +#include "libavutil/hwcontext_d3d11va.h" +#endif +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/time.h" + +#include "amfenc.h" +#include "internal.h" + +#if CONFIG_D3D11VA +#include +#endif + +#ifdef _WIN32 +#include "compat/w32dlfcn.h" +#else +#include +#endif + +#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" + +#define PTS_PROP L"PtsProp" + +const enum AVPixelFormat ff_amf_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUV420P, +#if CONFIG_D3D11VA + AV_PIX_FMT_D3D11, +#endif + AV_PIX_FMT_NONE +}; + +typedef struct FormatMap { + enum AVPixelFormat av_format; + enum AMF_SURFACE_FORMAT amf_format; +} FormatMap; + +static const FormatMap format_map[] = +{ + { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, + { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, + { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, + { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, + { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, + { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P }, + { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 }, + { AV_PIX_FMT_D3D11, AMF_SURFACE_NV12 }, +}; + + +static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + return desc->flags & AV_PIX_FMT_FLAG_HWACCEL; +} + + +static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) +{ + int i; + for (i = 0; i < amf_countof(format_map); i++) { + if (format_map[i].av_format == fmt) { + return format_map[i].amf_format; + } + } + return AMF_SURFACE_UNKNOWN; +} + +static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, + const wchar_t *scope, const wchar_t *message) +{ + AmfTraceWriter *tracer = (AmfTraceWriter*)pThis; + av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF +} + +static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis) +{ +} + +static AMFTraceWriterVtbl tracer_vtbl = +{ + .Write = AMFTraceWriter_Write, + .Flush = AMFTraceWriter_Flush, +}; + +static int amf_load_library(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + AMFInit_Fn init_fun = NULL; + AMFQueryVersion_Fn version_fun = NULL; + AMF_RESULT res = AMF_OK; + + ctx->eof = 0; + ctx->delayed_drain = 0; + ctx->hw_frames_ctx = NULL; + ctx->hw_device_ctx = NULL; + ctx->delayed_surface = NULL; + ctx->delayed_frame = av_frame_alloc(); + if (!ctx->delayed_frame) { + return AVERROR(ENOMEM); + } + // hardcoded to current HW queue size - will realloc in timestamp_queue_enqueue() if too small + ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * sizeof(int64_t)); + if (!ctx->timestamp_list) { + return AVERROR(ENOMEM); + } + ctx->dts_delay = 0; + + + ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL); + AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL, + AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA); + + init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME); + AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME); + + version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME); + AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME); + + res = version_fun(&ctx->version); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res); + res = init_fun(AMF_FULL_VERSION, &ctx->factory); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res); + res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res); + res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res); + return 0; +} + +static int amf_init_context(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + AMF_RESULT res = AMF_OK; + + // confugure AMF logger + // the return of these functions indicates old state and do not affect behaviour + ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); + if (ctx->log_to_dbg) + ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE); + ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0); + ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE); + + // connect AMF logger to av_log + ctx->tracer.vtbl = &tracer_vtbl; + ctx->tracer.avctx = avctx; + ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1); + ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE); + + res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res); + // try to reuse existing DX device +#if CONFIG_D3D11VA + if (avctx->hw_frames_ctx) { + AVHWFramesContext *device_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (device_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + if (amf_av_to_amf_format(device_ctx->sw_format) != AMF_SURFACE_UNKNOWN) { + if (device_ctx->device_ctx->hwctx) { + AVD3D11VADeviceContext *device_d3d11 = (AVD3D11VADeviceContext *)device_ctx->device_ctx->hwctx; + res = ctx->context->pVtbl->InitDX11(ctx->context, device_d3d11->device, AMF_DX11_1); + if (res == AMF_OK) { + ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); + if (!ctx->hw_frames_ctx) { + return AVERROR(ENOMEM); + } + } else { + if(res == AMF_NOT_SUPPORTED) + av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n"); + else + av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has non-AMD device, switching to default\n"); + } + } + } else { + av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has format not uspported by AMF, switching to default\n"); + } + } + } else if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data); + if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + if (device_ctx->hwctx) { + AVD3D11VADeviceContext *device_d3d11 = (AVD3D11VADeviceContext *)device_ctx->hwctx; + res = ctx->context->pVtbl->InitDX11(ctx->context, device_d3d11->device, AMF_DX11_1); + if (res == AMF_OK) { + ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); + if (!ctx->hw_device_ctx) { + return AVERROR(ENOMEM); + } + } else { + if (res == AMF_NOT_SUPPORTED) + av_log(avctx, AV_LOG_INFO, "avctx->hw_device_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n"); + else + av_log(avctx, AV_LOG_INFO, "avctx->hw_device_ctx has non-AMD device, switching to default\n"); + } + } + } + } +#endif + if (!ctx->hw_frames_ctx && !ctx->hw_device_ctx) { + res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); + if (res != AMF_OK) { + res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "InitDX9() failed with error %d\n", res); + } + } + return 0; +} + +static int amf_init_encoder(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + const wchar_t *codec_id = NULL; + AMF_RESULT res = AMF_OK; + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + codec_id = AMFVideoEncoderVCE_AVC; + break; + case AV_CODEC_ID_HEVC: + codec_id = AMFVideoEncoder_HEVC; + break; + default: + break; + } + AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); + + ctx->format = amf_av_to_amf_format(avctx->pix_fmt); + AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), "Format %d is not supported\n", avctx->pix_fmt); + + res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); + + return 0; +} + +int av_cold ff_amf_encode_close(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + if (ctx->delayed_surface) + { + ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); + ctx->delayed_surface = NULL; + } + + if (ctx->encoder) { + ctx->encoder->pVtbl->Terminate(ctx->encoder); + ctx->encoder->pVtbl->Release(ctx->encoder); + ctx->encoder = NULL; + } + + if (ctx->context) { + ctx->context->pVtbl->Terminate(ctx->context); + ctx->context->pVtbl->Release(ctx->context); + ctx->context = NULL; + } + av_buffer_unref(&ctx->hw_device_ctx); + av_buffer_unref(&ctx->hw_frames_ctx); + + if (ctx->trace) { + ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID); + } + if (ctx->library) { + dlclose(ctx->library); + ctx->library = NULL; + } + ctx->trace = NULL; + ctx->debug = NULL; + ctx->factory = NULL; + ctx->version = 0; + ctx->delayed_drain = 0; + av_frame_free(&ctx->delayed_frame); + av_fifo_freep(&ctx->timestamp_list); + + return 0; +} + +static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, + AMFSurface* surface) +{ + AVFrame *sw_frame = NULL; + AMFPlane *plane = NULL; + uint8_t *dst_data[4]; + int dst_linesize[4]; + int ret = 0; + int planes; + int i; + + if (frame->hw_frames_ctx && is_hwaccel_pix_fmt(frame->format)) { + if (!(sw_frame = av_frame_alloc())) { + av_log(avctx, AV_LOG_ERROR, "Can not alloc frame\n"); + ret = AVERROR(ENOMEM); + goto fail; + } + if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error transferring the data to system memory\n"); + goto fail; + } + frame = sw_frame; + } + planes = (int)surface->pVtbl->GetPlanesCount(surface); + if (planes > amf_countof(dst_data)) { + av_log(avctx, AV_LOG_ERROR, "Invalid number of planes %d in surface\n", planes); + ret = AVERROR(EINVAL); + goto fail; + } + + for (i = 0; i < planes; i++) { + plane = surface->pVtbl->GetPlaneAt(surface, i); + dst_data[i] = plane->pVtbl->GetNative(plane); + dst_linesize[i] = plane->pVtbl->GetHPitch(plane); + } + av_image_copy(dst_data, dst_linesize, + (const uint8_t**)frame->data, frame->linesize, frame->format, + avctx->width, avctx->height); + +fail: + if (sw_frame) { + av_frame_free(&sw_frame); + } + return ret; +} + +static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp) +{ + AmfContext *ctx = avctx->priv_data; + if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)) { + if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) { + return AVERROR(ENOMEM); + } + } + av_fifo_generic_write(ctx->timestamp_list, ×tamp, sizeof(timestamp), NULL); + return 0; +} + +static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) +{ + AmfContext *ctx = avctx->priv_data; + int ret; + AMFVariantStruct var = {0}; + int64_t timestamp = AV_NOPTS_VALUE; + int64_t size = buffer->pVtbl->GetSize(buffer); + + if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) { + return ret; + } + memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size); + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var); + if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) { + pkt->flags = AV_PKT_FLAG_KEY; + } + break; + case AV_CODEC_ID_HEVC: + buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var); + if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) { + pkt->flags = AV_PKT_FLAG_KEY; + } + break; + default: + break; + } + + buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var); + + pkt->pts = var.int64Value; // original pts + + + AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, "timestamp_list is empty\n"); + + av_fifo_generic_read(ctx->timestamp_list, ×tamp, sizeof(timestamp), NULL); + + // calc dts shift if max_b_frames > 0 + if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) { + int64_t timestamp_last = AV_NOPTS_VALUE; + AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, + "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames); + av_fifo_generic_peek_at( + ctx->timestamp_list, + ×tamp_last, + (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * sizeof(timestamp_last), + sizeof(timestamp_last), + NULL); + if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) { + return AVERROR(ERANGE); + } + ctx->dts_delay = timestamp_last - timestamp; + } + pkt->dts = timestamp - ctx->dts_delay; + return 0; +} + +// amfenc API implmentation +int ff_amf_encode_init(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + int ret; + + ctx->factory = NULL; + ctx->debug = NULL; + ctx->trace = NULL; + ctx->context = NULL; + ctx->encoder = NULL; + ctx->library = NULL; + ctx->version = 0; + ctx->eof = 0; + ctx->format = 0; + ctx->tracer.vtbl = NULL; + ctx->tracer.avctx = NULL; + + if ((ret = amf_load_library(avctx)) == 0) { + if ((ret = amf_init_context(avctx)) == 0) { + if ((ret = amf_init_encoder(avctx)) == 0) { + return 0; + } + } + } + ff_amf_encode_close(avctx); + return ret; +} + + +int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) +{ + AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMFSurface *surface = NULL; + int ret; + + if (!ctx->encoder) + return AVERROR(EINVAL); + + if (!frame) { // submit drain + if (!ctx->eof) { // submit drain one time only + if (ctx->delayed_surface != NULL) { + ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet + } else if(!ctx->delayed_drain) { + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res == AMF_INPUT_FULL) { + ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet + } else { + if (res == AMF_OK) { + ctx->eof = 1; // drain started + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res); + } + } + } else{ + return AVERROR_EOF; + } + } else { // submit frame + if (ctx->delayed_surface != NULL) { + return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit + } + // prepare surface from frame + if (frame->hw_frames_ctx && ( // HW frame detected + // check if the same hw_frames_ctx as used in initialization + (ctx->hw_frames_ctx && frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data) || + // check if the same hw_device_ctx as used in initialization + (ctx->hw_device_ctx && ((AVHWFramesContext*)frame->hw_frames_ctx->data)->device_ctx == + (AVHWDeviceContext*)ctx->hw_device_ctx->data) + )) { +#if CONFIG_D3D11VA + static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; + ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture + int index = (int)(size_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use + texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); + + res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); + + // input HW surfaces can be vertically aligned by 16; tell AMF the real size + surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); +#endif + } else { + res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res); + amf_copy_surface(avctx, frame, surface); + } + surface->pVtbl->SetPts(surface, frame->pts); + AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts); + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); + break; + case AV_CODEC_ID_HEVC: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); + break; + default: + break; + } + + + // submit surface + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); + if (res == AMF_INPUT_FULL) { // handle full queue + //store surface for later submission + ctx->delayed_surface = surface; + if (surface->pVtbl->GetMemoryType(surface) == AMF_MEMORY_DX11) { + av_frame_ref(ctx->delayed_frame, frame); + } + } else { + surface->pVtbl->Release(surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); + + if ((ret = timestamp_queue_enqueue(avctx, frame->pts)) < 0) { + return ret; + } + + } + } + return 0; +} +int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) +{ + int ret; + AMF_RESULT res; + AMF_RESULT res_query; + AmfContext *ctx = avctx->priv_data; + AMFData *data = NULL; + int block_and_wait; + + if (!ctx->encoder) + return AVERROR(EINVAL); + + do { + block_and_wait = 0; + // poll data + res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); + if (data) { + // copy data to packet + AMFBuffer* buffer; + AMFGuid guid = IID_AMFBuffer(); + data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface + ret = amf_copy_buffer(avctx, avpkt, buffer); + + buffer->pVtbl->Release(buffer); + data->pVtbl->Release(data); + + AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); + + if (ctx->delayed_surface != NULL) { // try to resubmit frame + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface); + if (res != AMF_INPUT_FULL) { + int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface); + ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); + ctx->delayed_surface = NULL; + av_frame_unref(ctx->delayed_frame); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res); + + if ((ret = timestamp_queue_enqueue(avctx, pts)) < 0) { + return ret; + } + } else { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed frame submission got AMF_INPUT_FULL- should not happen\n"); + } + } else if (ctx->delayed_drain) { // try to resubmit drain + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res != AMF_INPUT_FULL) { + ctx->delayed_drain = 0; + ctx->eof = 1; // drain started + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); + } else { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); + } + } + } else if (ctx->delayed_surface != NULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF)) { + block_and_wait = 1; + av_usleep(1000); // wait and poll again + } + } while (block_and_wait); + + if (res_query == AMF_EOF) { + ret = AVERROR_EOF; + } else if (data == NULL) { + ret = AVERROR(EAGAIN); + } else { + ret = 0; + } + return ret; +} diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h new file mode 100644 index 000000000..84f0aad2f --- /dev/null +++ b/libavcodec/amfenc.h @@ -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 +*/ + +#ifndef AVCODEC_AMFENC_H +#define AVCODEC_AMFENC_H + +#include + +#include +#include + +#include "libavutil/fifo.h" + +#include "avcodec.h" + + +/** +* AMF trace writer callback class +* Used to capture all AMF logging +*/ + +typedef struct AmfTraceWriter { + AMFTraceWriterVtbl *vtbl; + AVCodecContext *avctx; +} AmfTraceWriter; + +/** +* AMF encoder context +*/ + +typedef struct AmfContext { + AVClass *avclass; + // access to AMF runtime + amf_handle library; ///< handle to DLL library + AMFFactory *factory; ///< pointer to AMF factory + AMFDebug *debug; ///< pointer to AMF debug interface + AMFTrace *trace; ///< pointer to AMF trace interface + + amf_uint64 version; ///< version of AMF runtime + AmfTraceWriter tracer; ///< AMF writer registered with AMF + AMFContext *context; ///< AMF context + //encoder + AMFComponent *encoder; ///< AMF encoder object + amf_bool eof; ///< flag indicating EOF happened + AMF_SURFACE_FORMAT format; ///< AMF surface format + + AVBufferRef *hw_device_ctx; ///< pointer to HW accelerator (decoder) + AVBufferRef *hw_frames_ctx; ///< pointer to HW accelerator (frame allocator) + + // helpers to handle async calls + int delayed_drain; + AMFSurface *delayed_surface; + AVFrame *delayed_frame; + + // shift dts back by max_b_frames in timing + AVFifoBuffer *timestamp_list; + int64_t dts_delay; + + // common encoder option options + + int log_to_dbg; + + // Static options, have to be set before Init() call + int usage; + int profile; + int level; + int preanalysis; + int quality; + int b_frame_delta_qp; + int ref_b_frame_delta_qp; + + // Dynamic options, can be set after Init() call + + int rate_control_mode; + int enforce_hrd; + int filler_data; + int enable_vbaq; + int skip_frame; + int qp_i; + int qp_p; + int qp_b; + int max_au_size; + int header_spacing; + int b_frame_ref; + int intra_refresh_mb; + int coding_mode; + int me_half_pel; + int me_quarter_pel; + int aud; + + // HEVC - specific options + + int gops_per_idr; + int header_insertion_mode; + int min_qp_i; + int max_qp_i; + int min_qp_p; + int max_qp_p; + int tier; +} AmfContext; + +/** +* Common encoder initization function +*/ +int ff_amf_encode_init(AVCodecContext *avctx); +/** +* Common encoder termination function +*/ +int ff_amf_encode_close(AVCodecContext *avctx); + +/** +* Ecoding one frame - common function for all AMF encoders +*/ + +int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame); +int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); + +/** +* Supported formats +*/ +extern const enum AVPixelFormat ff_amf_pix_fmts[]; + +/** +* Error handling helper +*/ +#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value, /*message,*/ ...) \ + if (!(exp)) { \ + av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \ + return ret_value; \ + } + +#endif //AVCODEC_AMFENC_H diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c new file mode 100644 index 000000000..96e4e952d --- /dev/null +++ b/libavcodec/amfenc_h264.c @@ -0,0 +1,395 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/internal.h" +#include "libavutil/opt.h" +#include "amfenc.h" +#include "internal.h" + +#define OFFSET(x) offsetof(AmfContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption options[] = { + // Static + /// Usage + { "usage", "Encoder Usage", OFFSET(usage), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCONDING }, AMF_VIDEO_ENCODER_USAGE_TRANSCONDING, AMF_VIDEO_ENCODER_USAGE_WEBCAM, VE, "usage" }, + { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCONDING }, 0, 0, VE, "usage" }, + { "ultralowlatency","", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "lowlatency", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_WEBCAM }, 0, 0, VE, "usage" }, + + /// Profile, + { "profile", "Profile", OFFSET(profile),AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, AMF_VIDEO_ENCODER_PROFILE_BASELINE, AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH, VE, "profile" }, + { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, 0, 0, VE, "profile" }, + { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_HIGH }, 0, 0, VE, "profile" }, + { "constrained_baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE }, 0, 0, VE, "profile" }, + { "constrained_high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH }, 0, 0, VE, "profile" }, + + /// Profile Level + { "level", "Profile Level", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 62, VE, "level" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "level" }, + { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 10 }, 0, 0, VE, "level" }, + { "1.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 11 }, 0, 0, VE, "level" }, + { "1.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 12 }, 0, 0, VE, "level" }, + { "1.3", "", 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, 0, 0, VE, "level" }, + { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 20 }, 0, 0, VE, "level" }, + { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 21 }, 0, 0, VE, "level" }, + { "2.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 22 }, 0, 0, VE, "level" }, + { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level" }, + { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, 0, 0, VE, "level" }, + { "3.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, 0, 0, VE, "level" }, + { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, 0, 0, VE, "level" }, + { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, 0, 0, VE, "level" }, + { "4.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, 0, 0, VE, "level" }, + { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, 0, 0, VE, "level" }, + { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, 0, 0, VE, "level" }, + { "5.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, 0, 0, VE, "level" }, + { "6.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 60 }, 0, 0, VE, "level" }, + { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 61 }, 0, 0, VE, "level" }, + { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 62 }, 0, 0, VE, "level" }, + + + /// Quality Preset + { "quality", "Quality Preference", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, VE, "quality" }, + { "speed", "Prefer Speed", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, 0, 0, VE, "quality" }, + { "balanced", "Balanced", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED }, 0, 0, VE, "quality" }, + { "quality", "Prefer Quality", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY }, 0, 0, VE, "quality" }, + + // Dynamic + /// Rate Control Method + { "rc", "Rate Control Method", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, VE, "rc" }, + { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, "rc" }, + { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, "rc" }, + { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + + /// Enforce HRD, Filler Data, VBAQ, Frame Skipping + { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "frame_skipping", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + /// QP Values + { "qp_i", "Quantization Parameter for I-Frame", OFFSET(qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_p", "Quantization Parameter for P-Frame", OFFSET(qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_b", "Quantization Parameter for B-Frame", OFFSET(qp_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + + /// Pre-Pass, Pre-Analysis, Two-Pass + { "preanalysis", "Pre-Analysis Mode", OFFSET(preanalysis), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE, NULL }, + + /// Maximum Access Unit Size + { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + + /// Header Insertion Spacing + { "header_spacing", "Header Insertion Spacing", OFFSET(header_spacing), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1000, VE }, + + /// B-Frames + // BPicturesPattern=bf + { "bf_delta_qp", "B-Picture Delta QP", OFFSET(b_frame_delta_qp), AV_OPT_TYPE_INT, { .i64 = 4 }, -10, 10, VE }, + { "bf_ref", "Enable Reference to B-Frames", OFFSET(b_frame_ref), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "bf_ref_delta_qp","Reference B-Picture Delta QP", OFFSET(ref_b_frame_delta_qp), AV_OPT_TYPE_INT, { .i64 = 4 }, -10, 10, VE }, + + /// Intra-Refresh + { "intra_refresh_mb","Intra Refresh MBs Number Per Slot in Macroblocks", OFFSET(intra_refresh_mb), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + + /// coder + { "coder", "Coding Type", OFFSET(coding_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_UNDEFINED }, AMF_VIDEO_ENCODER_UNDEFINED, AMF_VIDEO_ENCODER_CALV, VE, "coder" }, + { "auto", "Automatic", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_UNDEFINED }, 0, 0, VE, "coder" }, + { "cavlc", "Context Adaptive Variable-Length Coding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_CALV }, 0, 0, VE, "coder" }, + { "cabac", "Context Adaptive Binary Arithmetic Coding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_CABAC }, 0, 0, VE, "coder" }, + + { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "me_quarter_pel", "Enable ME Quarter Pixel", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { NULL } +}; + +static av_cold int amf_encode_init_h264(AVCodecContext *avctx) +{ + int ret = 0; + AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMFVariantStruct var = { 0 }; + amf_int64 profile = 0; + amf_int64 profile_level = 0; + AMFBuffer *buffer; + AMFGuid guid; + AMFRate framerate; + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); + } else { + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num * avctx->ticks_per_frame); + } + + if ((ret = ff_amf_encode_init(avctx)) != 0) + return ret; + + // Static parameters + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_USAGE, ctx->usage); + + AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_FRAMESIZE, framesize); + + AMF_ASSIGN_PROPERTY_RATE(res, ctx->encoder, AMF_VIDEO_ENCODER_FRAMERATE, framerate); + + switch (avctx->profile) { + case FF_PROFILE_H264_BASELINE: + profile = AMF_VIDEO_ENCODER_PROFILE_BASELINE; + break; + case FF_PROFILE_H264_MAIN: + profile = AMF_VIDEO_ENCODER_PROFILE_MAIN; + break; + case FF_PROFILE_H264_HIGH: + profile = AMF_VIDEO_ENCODER_PROFILE_HIGH; + break; + case FF_PROFILE_H264_CONSTRAINED_BASELINE: + profile = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE; + break; + case (FF_PROFILE_H264_HIGH | FF_PROFILE_H264_CONSTRAINED): + profile = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH; + break; + } + if (profile == 0) { + profile = ctx->profile; + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE, profile); + + profile_level = avctx->level; + if (profile_level == FF_LEVEL_UNKNOWN) { + profile_level = ctx->level; + } + if (profile_level != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE_LEVEL, profile_level); + } + + // Maximum Reference Frames + if (avctx->refs != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_NUM_REFRAMES, avctx->refs); + } + if (avctx->sample_aspect_ratio.den && avctx->sample_aspect_ratio.num) { + AMFRatio ratio = AMFConstructRatio(avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_ASPECT_RATIO, ratio); + } + + /// Color Range (Partial/TV/MPEG or Full/PC/JPEG) + if (avctx->color_range == AVCOL_RANGE_JPEG) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FULL_RANGE_COLOR, 1); + } + + // autodetect rate control method + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN) { + if (ctx->qp_i != -1 || ctx->qp_p != -1 || ctx->qp_b != -1) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); + } else if (avctx->rc_max_rate > 0 ) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); + } else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); + } + } + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE, AMF_VIDEO_ENCODER_PREENCODE_DISABLED); + if (ctx->preanalysis) + av_log(ctx, AV_LOG_WARNING, "Pre-Analysis is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE, ctx->preanalysis); + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUALITY_PRESET, ctx->quality); + + // Dynamic parmaters + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, ctx->rate_control_mode); + + /// VBV Buffer + if (avctx->rc_buffer_size != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, avctx->rc_buffer_size); + if (avctx->rc_initial_buffer_occupancy != 0) { + int amf_buffer_fullness = avctx->rc_initial_buffer_occupancy * 64 / avctx->rc_buffer_size; + if (amf_buffer_fullness > 64) + amf_buffer_fullness = 64; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, amf_buffer_fullness); + } + } + /// Maximum Access Unit Size + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_AU_SIZE, ctx->max_au_size); + + if (ctx->max_au_size) + ctx->enforce_hrd = 1; + + // QP Minimum / Maximum + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MIN_QP, 0); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_QP, 51); + } else { + if (avctx->qmin != -1) { + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MIN_QP, qval); + } + if (avctx->qmax != -1) { + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_QP, qval); + } + } + // QP Values + if (ctx->qp_i != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_I, ctx->qp_i); + if (ctx->qp_p != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_P, ctx->qp_p); + if (ctx->qp_b != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_B, ctx->qp_b); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_TARGET_BITRATE, avctx->bit_rate); + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->bit_rate); + } + if (avctx->rc_max_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->rc_max_rate); + } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { + av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + } + + // Initialize Encoder + res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); + + // Enforce HRD, Filler Data, VBAQ, Frame Skipping, Deblocking Filter + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENFORCE_HRD, !!ctx->enforce_hrd); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, !!ctx->filler_data); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, !!ctx->skip_frame); + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, 0); + if (ctx->enable_vbaq) + av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, !!ctx->enable_vbaq); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, !!deblocking_filter); + + // B-Frames + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, avctx->max_b_frames); + if (res != AMF_OK) { + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, &var); + av_log(ctx, AV_LOG_WARNING, "B-frames=%d is not supported by this GPU, switched to %d\n", + avctx->max_b_frames, (int)var.int64Value); + avctx->max_b_frames = (int)var.int64Value; + } + if (avctx->max_b_frames) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, ctx->b_frame_delta_qp); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_B_REFERENCE_ENABLE, !!ctx->b_frame_ref); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, ctx->ref_b_frame_delta_qp); + } + + // Keyframe Interval + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_IDR_PERIOD, avctx->gop_size); + + // Header Insertion Spacing + if (ctx->header_spacing >= 0) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, ctx->header_spacing); + + // Intra-Refresh, Slicing + if (ctx->intra_refresh_mb > 0) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, ctx->intra_refresh_mb); + if (avctx->slices > 1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_SLICES_PER_FRAME, avctx->slices); + + // Coding + if (ctx->coding_mode != 0) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_CABAC_ENABLE, ctx->coding_mode); + + // Motion Estimation + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, !!ctx->me_half_pel); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, !!ctx->me_quarter_pel); + + // fill extradata + res = AMFVariantInit(&var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "AMFVariantInit() failed with error %d\n", res); + + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_EXTRADATA, &var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) failed with error %d\n", res); + AMF_RETURN_IF_FALSE(ctx, var.pInterface != NULL, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) returned NULL\n"); + + guid = IID_AMFBuffer(); + + res = var.pInterface->pVtbl->QueryInterface(var.pInterface, &guid, (void**)&buffer); // query for buffer interface + if (res != AMF_OK) { + var.pInterface->pVtbl->Release(var.pInterface); + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "QueryInterface(IID_AMFBuffer) failed with error %d\n", res); + + avctx->extradata_size = (int)buffer->pVtbl->GetSize(buffer); + avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + return AVERROR(ENOMEM); + } + memcpy(avctx->extradata, buffer->pVtbl->GetNative(buffer), avctx->extradata_size); + + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + + return 0; +} + +static const AVCodecDefault defaults[] = { + { "refs", "-1" }, + { "aspect", "0" }, + { "sar", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { "b", "2M" }, + { "g", "250" }, + { "slices", "1" }, + { NULL }, +}; + +static const AVClass h264_amf_class = { + .class_name = "h264_amf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; +//TODO declare as HW encoder when available +AVCodec ff_h264_amf_encoder = { + .name = "h264_amf", + .long_name = NULL_IF_CONFIG_SMALL("AMD AMF H.264 Encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .init = amf_encode_init_h264, + .send_frame = ff_amf_send_frame, + .receive_packet = ff_amf_receive_packet, + .close = ff_amf_encode_close, + .priv_data_size = sizeof(AmfContext), + .priv_class = &h264_amf_class, + .defaults = defaults, + .capabilities = AV_CODEC_CAP_DELAY, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .pix_fmts = ff_amf_pix_fmts, +}; diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c new file mode 100644 index 000000000..3956b2d17 --- /dev/null +++ b/libavcodec/amfenc_hevc.c @@ -0,0 +1,326 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/internal.h" +#include "libavutil/opt.h" +#include "amfenc.h" +#include "internal.h" + +#define OFFSET(x) offsetof(AmfContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING }, AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING, AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM, VE, "usage" }, + { "transcoding", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING }, 0, 0, VE, "usage" }, + { "ultralowlatency","", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "lowlatency", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "webcam", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM }, 0, 0, VE, "usage" }, + + { "profile", "Set the profile (default main)", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, VE, "profile" }, + { "main", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, 0, 0, VE, "profile" }, + + { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, AMF_VIDEO_ENCODER_HEVC_TIER_MAIN, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, "tier" }, + { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, 0, 0, VE, "tier" }, + { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_HIGH }, 0, 0, VE, "tier" }, + + { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, AMF_LEVEL_6_2, VE, "level" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "level" }, + { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_1 }, 0, 0, VE, "level" }, + { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_2 }, 0, 0, VE, "level" }, + { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_2_1 }, 0, 0, VE, "level" }, + { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_3 }, 0, 0, VE, "level" }, + { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_3_1 }, 0, 0, VE, "level" }, + { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_4 }, 0, 0, VE, "level" }, + { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_4_1 }, 0, 0, VE, "level" }, + { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_5 }, 0, 0, VE, "level" }, + { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_5_1 }, 0, 0, VE, "level" }, + { "5.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_5_2 }, 0, 0, VE, "level" }, + { "6.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6 }, 0, 0, VE, "level" }, + { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_1 }, 0, 0, VE, "level" }, + { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_2 }, 0, 0, VE, "level" }, + + { "quality", "Set the encoding quality", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, "quality" }, + { "balanced", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED }, 0, 0, VE, "quality" }, + { "speed", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, 0, 0, VE, "quality" }, + { "quality", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY }, 0, 0, VE, "quality" }, + + { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR, VE, "rc" }, + { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, "rc" }, + { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, "rc" }, + { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + + { "header_insertion_mode", "Set header insertion mode", OFFSET(header_insertion_mode), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED, VE, "hdrmode" }, + { "none", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, 0, 0, VE, "hdrmode" }, + { "gop", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, "hdrmode" }, + { "idr", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED }, 0, 0, VE, "hdrmode" }, + + { "gops_per_idr", "GOPs per IDR 0-no IDR will be inserted", OFFSET(gops_per_idr), AV_OPT_TYPE_INT, { .i64 = 60 }, 0, INT_MAX, VE }, + { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, INT_MAX, VE}, + { "min_qp_i", "min quantization parameter for I-frame", OFFSET(min_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "max_qp_i", "max quantization parameter for I-frame", OFFSET(max_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "min_qp_p", "min quantization parameter for P-frame", OFFSET(min_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "max_qp_p", "max quantization parameter for P-frame", OFFSET(max_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_p", "quantization parameter for P-frame", OFFSET(qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_i", "quantization parameter for I-frame", OFFSET(qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE }, + { "me_quarter_pel", "Enable ME Quarter Pixel ", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE }, + + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + + { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { NULL } +}; + +static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) +{ + int ret = 0; + AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMFVariantStruct var = {0}; + amf_int64 profile = 0; + amf_int64 profile_level = 0; + AMFBuffer *buffer; + AMFGuid guid; + AMFRate framerate; + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); + } else { + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num * avctx->ticks_per_frame); + } + + if ((ret = ff_amf_encode_init(avctx)) < 0) + return ret; + + // init static parameters + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_USAGE, ctx->usage); + + AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FRAMESIZE, framesize); + + AMF_ASSIGN_PROPERTY_RATE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FRAMERATE, framerate); + + switch (avctx->profile) { + case FF_PROFILE_HEVC_MAIN: + profile = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN; + break; + default: + break; + } + if (profile == 0) { + profile = ctx->profile; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE, profile); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TIER, ctx->tier); + + profile_level = avctx->level; + if (profile_level == 0) { + profile_level = ctx->level; + } + if (profile_level != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE_LEVEL, profile_level); + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET, ctx->quality); + // Maximum Reference Frames + if (avctx->refs != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_NUM_REFRAMES, avctx->refs); + } + // Aspect Ratio + if (avctx->sample_aspect_ratio.den && avctx->sample_aspect_ratio.num) { + AMFRatio ratio = AMFConstructRatio(avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO, ratio); + } + + // Picture control properties + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR, ctx->gops_per_idr); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_GOP_SIZE, avctx->gop_size); + if (avctx->slices > 1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_SLICES_PER_FRAME, avctx->slices); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_DE_BLOCKING_FILTER_DISABLE, deblocking_filter); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE, ctx->header_insertion_mode); + + // Rate control + // autodetect rate control method + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN) { + if (ctx->min_qp_i != -1 || ctx->max_qp_i != -1 || + ctx->min_qp_p != -1 || ctx->max_qp_p != -1 || + ctx->qp_i !=-1 || ctx->qp_p != -1) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); + } else if (avctx->rc_max_rate > 0) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); + } else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); + } + } + + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD, ctx->rate_control_mode); + if (avctx->rc_buffer_size) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_VBV_BUFFER_SIZE, avctx->rc_buffer_size); + + if (avctx->rc_initial_buffer_occupancy != 0) { + int amf_buffer_fullness = avctx->rc_initial_buffer_occupancy * 64 / avctx->rc_buffer_size; + if (amf_buffer_fullness > 64) + amf_buffer_fullness = 64; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INITIAL_VBV_BUFFER_FULLNESS, amf_buffer_fullness); + } + } + // Pre-Pass, Pre-Analysis, Two-Pass + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_PREANALYSIS_ENABLE, ctx->preanalysis); + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ, false); + if (ctx->enable_vbaq) + av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ, !!ctx->enable_vbaq); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_HALF_PIXEL, ctx->me_half_pel); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_QUARTERPIXEL, ctx->me_quarter_pel); + + // init dynamic rate control params + if (ctx->max_au_size) + ctx->enforce_hrd = 1; + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENFORCE_HRD, ctx->enforce_hrd); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FILLER_DATA_ENABLE, ctx->filler_data); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE, avctx->bit_rate); + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->bit_rate); + } + if (avctx->rc_max_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->rc_max_rate); + } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { + av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + } + + // init encoder + res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); + + // init dynamic picture control params + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_AU_SIZE, ctx->max_au_size); + + if (ctx->min_qp_i != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_I, ctx->min_qp_i); + } else if (avctx->qmin != -1) { + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_I, qval); + } + if (ctx->max_qp_i != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_I, ctx->max_qp_i); + } else if (avctx->qmax != -1) { + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_I, qval); + } + if (ctx->min_qp_p != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_P, ctx->min_qp_p); + } else if (avctx->qmin != -1) { + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_P, qval); + } + if (ctx->max_qp_p != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_P, ctx->max_qp_p); + } else if (avctx->qmax != -1) { + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_P, qval); + } + + if (ctx->qp_p != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QP_I, ctx->qp_p); + } + if (ctx->qp_i != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QP_P, ctx->qp_i); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_SKIP_FRAME_ENABLE, ctx->skip_frame); + + + // fill extradata + res = AMFVariantInit(&var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "AMFVariantInit() failed with error %d\n", res); + + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_EXTRADATA, &var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) failed with error %d\n", res); + AMF_RETURN_IF_FALSE(ctx, var.pInterface != NULL, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) returned NULL\n"); + + guid = IID_AMFBuffer(); + + res = var.pInterface->pVtbl->QueryInterface(var.pInterface, &guid, (void**)&buffer); // query for buffer interface + if (res != AMF_OK) { + var.pInterface->pVtbl->Release(var.pInterface); + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "QueryInterface(IID_AMFBuffer) failed with error %d\n", res); + + avctx->extradata_size = (int)buffer->pVtbl->GetSize(buffer); + avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + return AVERROR(ENOMEM); + } + memcpy(avctx->extradata, buffer->pVtbl->GetNative(buffer), avctx->extradata_size); + + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + + return 0; +} +static const AVCodecDefault defaults[] = { + { "refs", "-1" }, + { "aspect", "0" }, + { "sar", "0" }, + { "b", "2M" }, + { "g", "250" }, + { "slices", "1" }, + { NULL }, +}; +static const AVClass hevc_amf_class = { + .class_name = "hevc_amf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; +//TODO declare as HW encoder when available +AVCodec ff_hevc_amf_encoder = { + .name = "hevc_amf", + .long_name = NULL_IF_CONFIG_SMALL("AMD AMF HEVC encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .init = amf_encode_init_hevc, + .send_frame = ff_amf_send_frame, + .receive_packet = ff_amf_receive_packet, + .close = ff_amf_encode_close, + .priv_data_size = sizeof(AmfContext), + .priv_class = &hevc_amf_class, + .defaults = defaults, + .capabilities = AV_CODEC_CAP_DELAY, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .pix_fmts = ff_amf_pix_fmts, +}; diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c index 57aed874c..7f2874d35 100644 --- a/libavcodec/amrwbdec.c +++ b/libavcodec/amrwbdec.c @@ -611,7 +611,7 @@ static float voice_factor(float *p_vector, float p_gain, AMRWB_SFR_SIZE) * f_gain * f_gain; - return (p_ener - f_ener) / (p_ener + f_ener); + return (p_ener - f_ener) / (p_ener + f_ener + 0.01); } /** diff --git a/libavcodec/aptx.c b/libavcodec/aptx.c new file mode 100644 index 000000000..a35d2861c --- /dev/null +++ b/libavcodec/aptx.c @@ -0,0 +1,863 @@ +/* + * Audio Processing Technology codec for Bluetooth (aptX) + * + * Copyright (C) 2017 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 + */ + +#include "libavutil/intreadwrite.h" +#include "avcodec.h" +#include "internal.h" +#include "mathops.h" +#include "audio_frame_queue.h" + + +enum channels { + LEFT, + RIGHT, + NB_CHANNELS +}; + +enum subbands { + LF, // Low Frequency (0-5.5 kHz) + MLF, // Medium-Low Frequency (5.5-11kHz) + MHF, // Medium-High Frequency (11-16.5kHz) + HF, // High Frequency (16.5-22kHz) + NB_SUBBANDS +}; + +#define NB_FILTERS 2 +#define FILTER_TAPS 16 + +typedef struct { + int pos; + int32_t buffer[2*FILTER_TAPS]; +} FilterSignal; + +typedef struct { + FilterSignal outer_filter_signal[NB_FILTERS]; + FilterSignal inner_filter_signal[NB_FILTERS][NB_FILTERS]; +} QMFAnalysis; + +typedef struct { + int32_t quantized_sample; + int32_t quantized_sample_parity_change; + int32_t error; +} Quantize; + +typedef struct { + int32_t quantization_factor; + int32_t factor_select; + int32_t reconstructed_difference; +} InvertQuantize; + +typedef struct { + int32_t prev_sign[2]; + int32_t s_weight[2]; + int32_t d_weight[24]; + int32_t pos; + int32_t reconstructed_differences[48]; + int32_t previous_reconstructed_sample; + int32_t predicted_difference; + int32_t predicted_sample; +} Prediction; + +typedef struct { + int32_t codeword_history; + int32_t dither_parity; + int32_t dither[NB_SUBBANDS]; + + QMFAnalysis qmf; + Quantize quantize[NB_SUBBANDS]; + InvertQuantize invert_quantize[NB_SUBBANDS]; + Prediction prediction[NB_SUBBANDS]; +} Channel; + +typedef struct { + int32_t sync_idx; + Channel channels[NB_CHANNELS]; + AudioFrameQueue afq; +} AptXContext; + + +static const int32_t quantize_intervals_LF[65] = { + -9948, 9948, 29860, 49808, 69822, 89926, 110144, 130502, + 151026, 171738, 192666, 213832, 235264, 256982, 279014, 301384, + 324118, 347244, 370790, 394782, 419250, 444226, 469742, 495832, + 522536, 549890, 577936, 606720, 636290, 666700, 698006, 730270, + 763562, 797958, 833538, 870398, 908640, 948376, 989740, 1032874, + 1077948, 1125150, 1174700, 1226850, 1281900, 1340196, 1402156, 1468282, + 1539182, 1615610, 1698514, 1789098, 1888944, 2000168, 2125700, 2269750, + 2438670, 2642660, 2899462, 3243240, 3746078, 4535138, 5664098, 7102424, + 8897462, +}; +static const int32_t invert_quantize_dither_factors_LF[65] = { + 9948, 9948, 9962, 9988, 10026, 10078, 10142, 10218, + 10306, 10408, 10520, 10646, 10784, 10934, 11098, 11274, + 11462, 11664, 11880, 12112, 12358, 12618, 12898, 13194, + 13510, 13844, 14202, 14582, 14988, 15422, 15884, 16380, + 16912, 17484, 18098, 18762, 19480, 20258, 21106, 22030, + 23044, 24158, 25390, 26760, 28290, 30008, 31954, 34172, + 36728, 39700, 43202, 47382, 52462, 58762, 66770, 77280, + 91642, 112348, 144452, 199326, 303512, 485546, 643414, 794914, + 1000124, +}; +static const int32_t quantize_dither_factors_LF[65] = { + 0, 4, 7, 10, 13, 16, 19, 22, + 26, 28, 32, 35, 38, 41, 44, 47, + 51, 54, 58, 62, 65, 70, 74, 79, + 84, 90, 95, 102, 109, 116, 124, 133, + 143, 154, 166, 180, 195, 212, 231, 254, + 279, 308, 343, 383, 430, 487, 555, 639, + 743, 876, 1045, 1270, 1575, 2002, 2628, 3591, + 5177, 8026, 13719, 26047, 45509, 39467, 37875, 51303, + 0, +}; +static const int16_t quantize_factor_select_offset_LF[65] = { + 0, -21, -19, -17, -15, -12, -10, -8, + -6, -4, -1, 1, 3, 6, 8, 10, + 13, 15, 18, 20, 23, 26, 29, 31, + 34, 37, 40, 43, 47, 50, 53, 57, + 60, 64, 68, 72, 76, 80, 85, 89, + 94, 99, 105, 110, 116, 123, 129, 136, + 144, 152, 161, 171, 182, 194, 207, 223, + 241, 263, 291, 328, 382, 467, 522, 522, + 522, +}; + + +static const int32_t quantize_intervals_MLF[9] = { + -89806, 89806, 278502, 494338, 759442, 1113112, 1652322, 2720256, 5190186, +}; +static const int32_t invert_quantize_dither_factors_MLF[9] = { + 89806, 89806, 98890, 116946, 148158, 205512, 333698, 734236, 1735696, +}; +static const int32_t quantize_dither_factors_MLF[9] = { + 0, 2271, 4514, 7803, 14339, 32047, 100135, 250365, 0, +}; +static const int16_t quantize_factor_select_offset_MLF[9] = { + 0, -14, 6, 29, 58, 96, 154, 270, 521, +}; + + +static const int32_t quantize_intervals_MHF[3] = { + -194080, 194080, 890562, +}; +static const int32_t invert_quantize_dither_factors_MHF[3] = { + 194080, 194080, 502402, +}; +static const int32_t quantize_dither_factors_MHF[3] = { + 0, 77081, 0, +}; +static const int16_t quantize_factor_select_offset_MHF[3] = { + 0, -33, 136, +}; + + +static const int32_t quantize_intervals_HF[5] = { + -163006, 163006, 542708, 1120554, 2669238, +}; +static const int32_t invert_quantize_dither_factors_HF[5] = { + 163006, 163006, 216698, 361148, 1187538, +}; +static const int32_t quantize_dither_factors_HF[5] = { + 0, 13423, 36113, 206598, 0, +}; +static const int16_t quantize_factor_select_offset_HF[5] = { + 0, -8, 33, 95, 262, +}; + +typedef const struct { + const int32_t *quantize_intervals; + const int32_t *invert_quantize_dither_factors; + const int32_t *quantize_dither_factors; + const int16_t *quantize_factor_select_offset; + int tables_size; + int32_t quantized_bits; + int32_t prediction_order; +} ConstTables; + +static ConstTables tables[NB_SUBBANDS] = { + [LF] = { quantize_intervals_LF, + invert_quantize_dither_factors_LF, + quantize_dither_factors_LF, + quantize_factor_select_offset_LF, + FF_ARRAY_ELEMS(quantize_intervals_LF), + 7, 24 }, + [MLF] = { quantize_intervals_MLF, + invert_quantize_dither_factors_MLF, + quantize_dither_factors_MLF, + quantize_factor_select_offset_MLF, + FF_ARRAY_ELEMS(quantize_intervals_MLF), + 4, 12 }, + [MHF] = { quantize_intervals_MHF, + invert_quantize_dither_factors_MHF, + quantize_dither_factors_MHF, + quantize_factor_select_offset_MHF, + FF_ARRAY_ELEMS(quantize_intervals_MHF), + 2, 6 }, + [HF] = { quantize_intervals_HF, + invert_quantize_dither_factors_HF, + quantize_dither_factors_HF, + quantize_factor_select_offset_HF, + FF_ARRAY_ELEMS(quantize_intervals_HF), + 3, 12 }, +}; + +static const int16_t quantization_factors[32] = { + 2048, 2093, 2139, 2186, 2233, 2282, 2332, 2383, + 2435, 2489, 2543, 2599, 2656, 2714, 2774, 2834, + 2896, 2960, 3025, 3091, 3158, 3228, 3298, 3371, + 3444, 3520, 3597, 3676, 3756, 3838, 3922, 4008, +}; + + +/* Rounded right shift with optionnal clipping */ +#define RSHIFT_SIZE(size) \ +av_always_inline \ +static int##size##_t rshift##size(int##size##_t value, int shift) \ +{ \ + int##size##_t rounding = (int##size##_t)1 << (shift - 1); \ + int##size##_t mask = ((int##size##_t)1 << (shift + 1)) - 1; \ + return ((value + rounding) >> shift) - ((value & mask) == rounding); \ +} \ +av_always_inline \ +static int##size##_t rshift##size##_clip24(int##size##_t value, int shift) \ +{ \ + return av_clip_intp2(rshift##size(value, shift), 23); \ +} +RSHIFT_SIZE(32) +RSHIFT_SIZE(64) + + +av_always_inline +static void aptx_update_codeword_history(Channel *channel) +{ + int32_t cw = ((channel->quantize[0].quantized_sample & 3) << 0) + + ((channel->quantize[1].quantized_sample & 2) << 1) + + ((channel->quantize[2].quantized_sample & 1) << 3); + channel->codeword_history = (cw << 8) + (channel->codeword_history << 4); +} + +static void aptx_generate_dither(Channel *channel) +{ + int subband; + int64_t m; + int32_t d; + + aptx_update_codeword_history(channel); + + m = (int64_t)5184443 * (channel->codeword_history >> 7); + d = (m << 2) + (m >> 22); + for (subband = 0; subband < NB_SUBBANDS; subband++) + channel->dither[subband] = d << (23 - 5*subband); + channel->dither_parity = (d >> 25) & 1; +} + +/* + * Convolution filter coefficients for the outer QMF of the QMF tree. + * The 2 sets are a mirror of each other. + */ +static const int32_t aptx_qmf_outer_coeffs[NB_FILTERS][FILTER_TAPS] = { + { + 730, -413, -9611, 43626, -121026, 269973, -585547, 2801966, + 697128, -160481, 27611, 8478, -10043, 3511, 688, -897, + }, + { + -897, 688, 3511, -10043, 8478, 27611, -160481, 697128, + 2801966, -585547, 269973, -121026, 43626, -9611, -413, 730, + }, +}; + +/* + * Convolution filter coefficients for the inner QMF of the QMF tree. + * The 2 sets are a mirror of each other. + */ +static const int32_t aptx_qmf_inner_coeffs[NB_FILTERS][FILTER_TAPS] = { + { + 1033, -584, -13592, 61697, -171156, 381799, -828088, 3962579, + 985888, -226954, 39048, 11990, -14203, 4966, 973, -1268, + }, + { + -1268, 973, 4966, -14203, 11990, 39048, -226954, 985888, + 3962579, -828088, 381799, -171156, 61697, -13592, -584, 1033, + }, +}; + +/* + * Push one sample into a circular signal buffer. + */ +av_always_inline +static void aptx_qmf_filter_signal_push(FilterSignal *signal, int32_t sample) +{ + signal->buffer[signal->pos ] = sample; + signal->buffer[signal->pos+FILTER_TAPS] = sample; + signal->pos = (signal->pos + 1) & (FILTER_TAPS - 1); +} + +/* + * Compute the convolution of the signal with the coefficients, and reduce + * to 24 bits by applying the specified right shifting. + */ +av_always_inline +static int32_t aptx_qmf_convolution(FilterSignal *signal, + const int32_t coeffs[FILTER_TAPS], + int shift) +{ + int32_t *sig = &signal->buffer[signal->pos]; + int64_t e = 0; + int i; + + for (i = 0; i < FILTER_TAPS; i++) + e += MUL64(sig[i], coeffs[i]); + + return rshift64_clip24(e, shift); +} + +/* + * Half-band QMF analysis filter realized with a polyphase FIR filter. + * Split into 2 subbands and downsample by 2. + * So for each pair of samples that goes in, one sample goes out, + * split into 2 separate subbands. + */ +av_always_inline +static void aptx_qmf_polyphase_analysis(FilterSignal signal[NB_FILTERS], + const int32_t coeffs[NB_FILTERS][FILTER_TAPS], + int shift, + int32_t samples[NB_FILTERS], + int32_t *low_subband_output, + int32_t *high_subband_output) +{ + int32_t subbands[NB_FILTERS]; + int i; + + for (i = 0; i < NB_FILTERS; i++) { + aptx_qmf_filter_signal_push(&signal[i], samples[NB_FILTERS-1-i]); + subbands[i] = aptx_qmf_convolution(&signal[i], coeffs[i], shift); + } + + *low_subband_output = av_clip_intp2(subbands[0] + subbands[1], 23); + *high_subband_output = av_clip_intp2(subbands[0] - subbands[1], 23); +} + +/* + * Two stage QMF analysis tree. + * Split 4 input samples into 4 subbands and downsample by 4. + * So for each group of 4 samples that goes in, one sample goes out, + * split into 4 separate subbands. + */ +static void aptx_qmf_tree_analysis(QMFAnalysis *qmf, + int32_t samples[4], + int32_t subband_samples[4]) +{ + int32_t intermediate_samples[4]; + int i; + + /* Split 4 input samples into 2 intermediate subbands downsampled to 2 samples */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_analysis(qmf->outer_filter_signal, + aptx_qmf_outer_coeffs, 23, + &samples[2*i], + &intermediate_samples[0+i], + &intermediate_samples[2+i]); + + /* Split 2 intermediate subband samples into 4 final subbands downsampled to 1 sample */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_analysis(qmf->inner_filter_signal[i], + aptx_qmf_inner_coeffs, 23, + &intermediate_samples[2*i], + &subband_samples[2*i+0], + &subband_samples[2*i+1]); +} + +/* + * Half-band QMF synthesis filter realized with a polyphase FIR filter. + * Join 2 subbands and upsample by 2. + * So for each 2 subbands sample that goes in, a pair of samples goes out. + */ +av_always_inline +static void aptx_qmf_polyphase_synthesis(FilterSignal signal[NB_FILTERS], + const int32_t coeffs[NB_FILTERS][FILTER_TAPS], + int shift, + int32_t low_subband_input, + int32_t high_subband_input, + int32_t samples[NB_FILTERS]) +{ + int32_t subbands[NB_FILTERS]; + int i; + + subbands[0] = low_subband_input + high_subband_input; + subbands[1] = low_subband_input - high_subband_input; + + for (i = 0; i < NB_FILTERS; i++) { + aptx_qmf_filter_signal_push(&signal[i], subbands[1-i]); + samples[i] = aptx_qmf_convolution(&signal[i], coeffs[i], shift); + } +} + +/* + * Two stage QMF synthesis tree. + * Join 4 subbands and upsample by 4. + * So for each 4 subbands sample that goes in, a group of 4 samples goes out. + */ +static void aptx_qmf_tree_synthesis(QMFAnalysis *qmf, + int32_t subband_samples[4], + int32_t samples[4]) +{ + int32_t intermediate_samples[4]; + int i; + + /* Join 4 subbands into 2 intermediate subbands upsampled to 2 samples. */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_synthesis(qmf->inner_filter_signal[i], + aptx_qmf_inner_coeffs, 22, + subband_samples[2*i+0], + subband_samples[2*i+1], + &intermediate_samples[2*i]); + + /* Join 2 samples from intermediate subbands upsampled to 4 samples. */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_synthesis(qmf->outer_filter_signal, + aptx_qmf_outer_coeffs, 21, + intermediate_samples[0+i], + intermediate_samples[2+i], + &samples[2*i]); +} + + +av_always_inline +static int32_t aptx_bin_search(int32_t value, int32_t factor, + const int32_t *intervals, int32_t nb_intervals) +{ + int32_t idx = 0; + int i; + + for (i = nb_intervals >> 1; i > 0; i >>= 1) + if (MUL64(factor, intervals[idx + i]) <= ((int64_t)value << 24)) + idx += i; + + return idx; +} + +static void aptx_quantize_difference(Quantize *quantize, + int32_t sample_difference, + int32_t dither, + int32_t quantization_factor, + ConstTables *tables) +{ + const int32_t *intervals = tables->quantize_intervals; + int32_t quantized_sample, dithered_sample, parity_change; + int32_t d, mean, interval, inv; + int64_t error; + + quantized_sample = aptx_bin_search(FFABS(sample_difference) >> 4, + quantization_factor, + intervals, tables->tables_size); + + d = rshift32_clip24(MULH(dither, dither), 7) - (1 << 23); + d = rshift64(MUL64(d, tables->quantize_dither_factors[quantized_sample]), 23); + + intervals += quantized_sample; + mean = (intervals[1] + intervals[0]) / 2; + interval = (intervals[1] - intervals[0]) * (-(sample_difference < 0) | 1); + + dithered_sample = rshift64_clip24(MUL64(dither, interval) + ((int64_t)(mean + d) << 32), 32); + error = ((int64_t)FFABS(sample_difference) << 20) - MUL64(dithered_sample, quantization_factor); + quantize->error = FFABS(rshift64(error, 23)); + + parity_change = quantized_sample; + if (error < 0) + quantized_sample--; + else + parity_change--; + + inv = -(sample_difference < 0); + quantize->quantized_sample = quantized_sample ^ inv; + quantize->quantized_sample_parity_change = parity_change ^ inv; +} + +static void aptx_encode_channel(Channel *channel, int32_t samples[4]) +{ + int32_t subband_samples[4]; + int subband; + aptx_qmf_tree_analysis(&channel->qmf, samples, subband_samples); + aptx_generate_dither(channel); + for (subband = 0; subband < NB_SUBBANDS; subband++) { + int32_t diff = av_clip_intp2(subband_samples[subband] - channel->prediction[subband].predicted_sample, 23); + aptx_quantize_difference(&channel->quantize[subband], diff, + channel->dither[subband], + channel->invert_quantize[subband].quantization_factor, + &tables[subband]); + } +} + +static void aptx_decode_channel(Channel *channel, int32_t samples[4]) +{ + int32_t subband_samples[4]; + int subband; + for (subband = 0; subband < NB_SUBBANDS; subband++) + subband_samples[subband] = channel->prediction[subband].previous_reconstructed_sample; + aptx_qmf_tree_synthesis(&channel->qmf, subband_samples, samples); +} + + +static void aptx_invert_quantization(InvertQuantize *invert_quantize, + int32_t quantized_sample, int32_t dither, + ConstTables *tables) +{ + int32_t qr, idx, shift, factor_select; + + idx = (quantized_sample ^ -(quantized_sample < 0)) + 1; + qr = tables->quantize_intervals[idx] / 2; + if (quantized_sample < 0) + qr = -qr; + + qr = rshift64_clip24(((int64_t)qr<<32) + MUL64(dither, tables->invert_quantize_dither_factors[idx]), 32); + invert_quantize->reconstructed_difference = MUL64(invert_quantize->quantization_factor, qr) >> 19; + + shift = 24 - tables->quantized_bits; + + /* update factor_select */ + factor_select = 32620 * invert_quantize->factor_select; + factor_select = rshift32(factor_select + (tables->quantize_factor_select_offset[idx] << 15), 15); + invert_quantize->factor_select = av_clip(factor_select, 0, (shift << 8) | 0xFF); + + /* update quantization factor */ + idx = (invert_quantize->factor_select & 0xFF) >> 3; + shift -= invert_quantize->factor_select >> 8; + invert_quantize->quantization_factor = (quantization_factors[idx] << 11) >> shift; +} + +static int32_t *aptx_reconstructed_differences_update(Prediction *prediction, + int32_t reconstructed_difference, + int order) +{ + int32_t *rd1 = prediction->reconstructed_differences, *rd2 = rd1 + order; + int p = prediction->pos; + + rd1[p] = rd2[p]; + prediction->pos = p = (p + 1) % order; + rd2[p] = reconstructed_difference; + return &rd2[p]; +} + +static void aptx_prediction_filtering(Prediction *prediction, + int32_t reconstructed_difference, + int order) +{ + int32_t reconstructed_sample, predictor, srd0; + int32_t *reconstructed_differences; + int64_t predicted_difference = 0; + int i; + + reconstructed_sample = av_clip_intp2(reconstructed_difference + prediction->predicted_sample, 23); + predictor = av_clip_intp2((MUL64(prediction->s_weight[0], prediction->previous_reconstructed_sample) + + MUL64(prediction->s_weight[1], reconstructed_sample)) >> 22, 23); + prediction->previous_reconstructed_sample = reconstructed_sample; + + reconstructed_differences = aptx_reconstructed_differences_update(prediction, reconstructed_difference, order); + srd0 = FFDIFFSIGN(reconstructed_difference, 0) << 23; + for (i = 0; i < order; i++) { + int32_t srd = FF_SIGNBIT(reconstructed_differences[-i-1]) | 1; + prediction->d_weight[i] -= rshift32(prediction->d_weight[i] - srd*srd0, 8); + predicted_difference += MUL64(reconstructed_differences[-i], prediction->d_weight[i]); + } + + prediction->predicted_difference = av_clip_intp2(predicted_difference >> 22, 23); + prediction->predicted_sample = av_clip_intp2(predictor + prediction->predicted_difference, 23); +} + +static void aptx_process_subband(InvertQuantize *invert_quantize, + Prediction *prediction, + int32_t quantized_sample, int32_t dither, + ConstTables *tables) +{ + int32_t sign, same_sign[2], weight[2], sw1, range; + + aptx_invert_quantization(invert_quantize, quantized_sample, dither, tables); + + sign = FFDIFFSIGN(invert_quantize->reconstructed_difference, + -prediction->predicted_difference); + same_sign[0] = sign * prediction->prev_sign[0]; + same_sign[1] = sign * prediction->prev_sign[1]; + prediction->prev_sign[0] = prediction->prev_sign[1]; + prediction->prev_sign[1] = sign | 1; + + range = 0x100000; + sw1 = rshift32(-same_sign[1] * prediction->s_weight[1], 1); + sw1 = (av_clip(sw1, -range, range) & ~0xF) << 4; + + range = 0x300000; + weight[0] = 254 * prediction->s_weight[0] + 0x800000*same_sign[0] + sw1; + prediction->s_weight[0] = av_clip(rshift32(weight[0], 8), -range, range); + + range = 0x3C0000 - prediction->s_weight[0]; + weight[1] = 255 * prediction->s_weight[1] + 0xC00000*same_sign[1]; + prediction->s_weight[1] = av_clip(rshift32(weight[1], 8), -range, range); + + aptx_prediction_filtering(prediction, + invert_quantize->reconstructed_difference, + tables->prediction_order); +} + +static void aptx_invert_quantize_and_prediction(Channel *channel) +{ + int subband; + for (subband = 0; subband < NB_SUBBANDS; subband++) + aptx_process_subband(&channel->invert_quantize[subband], + &channel->prediction[subband], + channel->quantize[subband].quantized_sample, + channel->dither[subband], + &tables[subband]); +} + +static int32_t aptx_quantized_parity(Channel *channel) +{ + int32_t parity = channel->dither_parity; + int subband; + + for (subband = 0; subband < NB_SUBBANDS; subband++) + parity ^= channel->quantize[subband].quantized_sample; + + return parity & 1; +} + +/* For each sample, ensure that the parity of all subbands of all channels + * is 0 except once every 8 samples where the parity is forced to 1. */ +static int aptx_check_parity(Channel channels[NB_CHANNELS], int32_t *idx) +{ + int32_t parity = aptx_quantized_parity(&channels[LEFT]) + ^ aptx_quantized_parity(&channels[RIGHT]); + + int eighth = *idx == 7; + *idx = (*idx + 1) & 7; + + return parity ^ eighth; +} + +static void aptx_insert_sync(Channel channels[NB_CHANNELS], int32_t *idx) +{ + if (aptx_check_parity(channels, idx)) { + int i; + Channel *c; + static const int map[] = { 1, 2, 0, 3 }; + Quantize *min = &channels[NB_CHANNELS-1].quantize[map[0]]; + for (c = &channels[NB_CHANNELS-1]; c >= channels; c--) + for (i = 0; i < NB_SUBBANDS; i++) + if (c->quantize[map[i]].error < min->error) + min = &c->quantize[map[i]]; + + /* Forcing the desired parity is done by offsetting by 1 the quantized + * sample from the subband featuring the smallest quantization error. */ + min->quantized_sample = min->quantized_sample_parity_change; + } +} + +static uint16_t aptx_pack_codeword(Channel *channel) +{ + int32_t parity = aptx_quantized_parity(channel); + return (((channel->quantize[3].quantized_sample & 0x06) | parity) << 13) + | (((channel->quantize[2].quantized_sample & 0x03) ) << 11) + | (((channel->quantize[1].quantized_sample & 0x0F) ) << 7) + | (((channel->quantize[0].quantized_sample & 0x7F) ) << 0); +} + +static void aptx_unpack_codeword(Channel *channel, uint16_t codeword) +{ + channel->quantize[0].quantized_sample = sign_extend(codeword >> 0, 7); + channel->quantize[1].quantized_sample = sign_extend(codeword >> 7, 4); + channel->quantize[2].quantized_sample = sign_extend(codeword >> 11, 2); + channel->quantize[3].quantized_sample = sign_extend(codeword >> 13, 3); + channel->quantize[3].quantized_sample = (channel->quantize[3].quantized_sample & ~1) + | aptx_quantized_parity(channel); +} + +static void aptx_encode_samples(AptXContext *ctx, + int32_t samples[NB_CHANNELS][4], + uint8_t output[2*NB_CHANNELS]) +{ + int channel; + for (channel = 0; channel < NB_CHANNELS; channel++) + aptx_encode_channel(&ctx->channels[channel], samples[channel]); + + aptx_insert_sync(ctx->channels, &ctx->sync_idx); + + for (channel = 0; channel < NB_CHANNELS; channel++) { + aptx_invert_quantize_and_prediction(&ctx->channels[channel]); + AV_WB16(output + 2*channel, aptx_pack_codeword(&ctx->channels[channel])); + } +} + +static int aptx_decode_samples(AptXContext *ctx, + const uint8_t input[2*NB_CHANNELS], + int32_t samples[NB_CHANNELS][4]) +{ + int channel, ret; + + for (channel = 0; channel < NB_CHANNELS; channel++) { + uint16_t codeword; + aptx_generate_dither(&ctx->channels[channel]); + + codeword = AV_RB16(input + 2*channel); + aptx_unpack_codeword(&ctx->channels[channel], codeword); + aptx_invert_quantize_and_prediction(&ctx->channels[channel]); + } + + ret = aptx_check_parity(ctx->channels, &ctx->sync_idx); + + for (channel = 0; channel < NB_CHANNELS; channel++) + aptx_decode_channel(&ctx->channels[channel], samples[channel]); + + return ret; +} + + +static av_cold int aptx_init(AVCodecContext *avctx) +{ + AptXContext *s = avctx->priv_data; + int chan, subband; + + if (avctx->frame_size == 0) + avctx->frame_size = 1024; + + if (avctx->frame_size & 3) { + av_log(avctx, AV_LOG_ERROR, "Frame size must be a multiple of 4 samples\n"); + return AVERROR(EINVAL); + } + + for (chan = 0; chan < NB_CHANNELS; chan++) { + Channel *channel = &s->channels[chan]; + for (subband = 0; subband < NB_SUBBANDS; subband++) { + Prediction *prediction = &channel->prediction[subband]; + prediction->prev_sign[0] = 1; + prediction->prev_sign[1] = 1; + } + } + + ff_af_queue_init(avctx, &s->afq); + return 0; +} + +static int aptx_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + AptXContext *s = avctx->priv_data; + AVFrame *frame = data; + int pos, channel, sample, ret; + + if (avpkt->size < 4) { + av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); + return AVERROR_INVALIDDATA; + } + + /* get output buffer */ + frame->channels = NB_CHANNELS; + frame->format = AV_SAMPLE_FMT_S32P; + frame->nb_samples = avpkt->size & ~3; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (pos = 0; pos < frame->nb_samples; pos += 4) { + int32_t samples[NB_CHANNELS][4]; + + if (aptx_decode_samples(s, &avpkt->data[pos], samples)) { + av_log(avctx, AV_LOG_ERROR, "Synchronization error\n"); + return AVERROR_INVALIDDATA; + } + + for (channel = 0; channel < NB_CHANNELS; channel++) + for (sample = 0; sample < 4; sample++) + AV_WN32A(&frame->data[channel][4*(sample+pos)], + samples[channel][sample] << 8); + } + + *got_frame_ptr = 1; + return frame->nb_samples; +} + +static int aptx_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + AptXContext *s = avctx->priv_data; + int pos, channel, sample, ret; + + if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) + return ret; + + if ((ret = ff_alloc_packet2(avctx, avpkt, frame->nb_samples, 0)) < 0) + return ret; + + for (pos = 0; pos < frame->nb_samples; pos += 4) { + int32_t samples[NB_CHANNELS][4]; + + for (channel = 0; channel < NB_CHANNELS; channel++) + for (sample = 0; sample < 4; sample++) + samples[channel][sample] = (int32_t)AV_RN32A(&frame->data[channel][4*(sample+pos)]) >> 8; + + aptx_encode_samples(s, samples, avpkt->data + pos); + } + + ff_af_queue_remove(&s->afq, frame->nb_samples, &avpkt->pts, &avpkt->duration); + *got_packet_ptr = 1; + return 0; +} + +static av_cold int aptx_close(AVCodecContext *avctx) +{ + AptXContext *s = avctx->priv_data; + ff_af_queue_close(&s->afq); + return 0; +} + + +#if CONFIG_APTX_DECODER +AVCodec ff_aptx_decoder = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("aptX (Audio Processing Technology for Bluetooth)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_APTX, + .priv_data_size = sizeof(AptXContext), + .init = aptx_init, + .decode = aptx_decode_frame, + .close = aptx_close, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_NONE }, +}; +#endif + +#if CONFIG_APTX_ENCODER +AVCodec ff_aptx_encoder = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("aptX (Audio Processing Technology for Bluetooth)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_APTX, + .priv_data_size = sizeof(AptXContext), + .init = aptx_init, + .encode2 = aptx_encode_frame, + .close = aptx_close, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, +}; +#endif diff --git a/libavcodec/arm/fmtconvert_init_arm.c b/libavcodec/arm/fmtconvert_init_arm.c index a734decec..e88255d61 100644 --- a/libavcodec/arm/fmtconvert_init_arm.c +++ b/libavcodec/arm/fmtconvert_init_arm.c @@ -42,10 +42,8 @@ av_cold void ff_fmt_convert_init_arm(FmtConvertContext *c, AVCodecContext *avctx int cpu_flags = av_get_cpu_flags(); if (have_vfp_vm(cpu_flags)) { - if (!have_vfpv3(cpu_flags)) { - c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_vfp; - c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_vfp; - } + c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_vfp; + c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_vfp; } if (have_neon(cpu_flags)) { diff --git a/libavcodec/arm/h264idct_neon.S b/libavcodec/arm/h264idct_neon.S index 4f68bdb9f..93859db88 100644 --- a/libavcodec/arm/h264idct_neon.S +++ b/libavcodec/arm/h264idct_neon.S @@ -21,6 +21,7 @@ #include "libavutil/arm/asm.S" function ff_h264_idct_add_neon, export=1 +h264_idct_add_neon_nothumb: vld1.64 {d0-d3}, [r1,:128] vmov.i16 q15, #0 @@ -73,6 +74,7 @@ function ff_h264_idct_add_neon, export=1 endfunc function ff_h264_idct_dc_add_neon, export=1 +h264_idct_dc_add_neon_nothumb: mov r3, #0 vld1.16 {d2[],d3[]}, [r1,:16] strh r3, [r1] @@ -113,8 +115,8 @@ function ff_h264_idct_add16_neon, export=1 movne lr, #0 cmp lr, #0 ite ne - adrne lr, X(ff_h264_idct_dc_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct_add_neon) + CONFIG_THUMB + adrne lr, h264_idct_dc_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct_add_neon_nothumb + CONFIG_THUMB blx lr 2: subs ip, ip, #1 add r1, r1, #32 @@ -138,8 +140,8 @@ function ff_h264_idct_add16intra_neon, export=1 cmp r8, #0 ldrsh r8, [r1] iteet ne - adrne lr, X(ff_h264_idct_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct_dc_add_neon) + CONFIG_THUMB + adrne lr, h264_idct_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct_dc_add_neon_nothumb + CONFIG_THUMB cmpeq r8, #0 blxne lr subs ip, ip, #1 @@ -166,8 +168,8 @@ function ff_h264_idct_add8_neon, export=1 cmp r8, #0 ldrsh r8, [r1] iteet ne - adrne lr, X(ff_h264_idct_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct_dc_add_neon) + CONFIG_THUMB + adrne lr, h264_idct_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct_dc_add_neon_nothumb + CONFIG_THUMB cmpeq r8, #0 blxne lr add r12, r12, #1 @@ -267,6 +269,7 @@ endfunc .endm function ff_h264_idct8_add_neon, export=1 +h264_idct8_add_neon_nothumb: vmov.i16 q3, #0 vld1.16 {q8-q9}, [r1,:128] vst1.16 {q3}, [r1,:128]! @@ -328,6 +331,7 @@ function ff_h264_idct8_add_neon, export=1 endfunc function ff_h264_idct8_dc_add_neon, export=1 +h264_idct8_dc_add_neon_nothumb: mov r3, #0 vld1.16 {d30[],d31[]},[r1,:16] strh r3, [r1] @@ -388,8 +392,8 @@ function ff_h264_idct8_add4_neon, export=1 movne lr, #0 cmp lr, #0 ite ne - adrne lr, X(ff_h264_idct8_dc_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct8_add_neon) + CONFIG_THUMB + adrne lr, h264_idct8_dc_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct8_add_neon_nothumb + CONFIG_THUMB blx lr 2: subs r12, r12, #4 add r1, r1, #128 diff --git a/libavcodec/arm/hevcdsp_arm.h b/libavcodec/arm/hevcdsp_arm.h index 7735df9cd..47cdfa574 100644 --- a/libavcodec/arm/hevcdsp_arm.h +++ b/libavcodec/arm/hevcdsp_arm.h @@ -21,6 +21,6 @@ #include "libavcodec/hevcdsp.h" -void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth); +void ff_hevc_dsp_init_neon(HEVCDSPContext *c, const int bit_depth); #endif /* AVCODEC_ARM_HEVCDSP_ARM_H */ diff --git a/libavcodec/arm/hevcdsp_idct_neon.S b/libavcodec/arm/hevcdsp_idct_neon.S index e39d00634..75795e6a6 100644 --- a/libavcodec/arm/hevcdsp_idct_neon.S +++ b/libavcodec/arm/hevcdsp_idct_neon.S @@ -1,5 +1,7 @@ /* + * ARM NEON optimised IDCT functions for HEVC decoding * Copyright (c) 2014 Seppo Tomperi + * Copyright (c) 2017 Alexandra Hájková * * This file is part of FFmpeg. * @@ -19,179 +21,967 @@ */ #include "libavutil/arm/asm.S" -#include "neon.S" -function ff_hevc_idct_4x4_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - vdup.16 q0, r1 - vdup.16 q1, r1 - vst1.16 {q0, q1}, [r0] - bx lr -endfunc +const trans, align=4 + .short 64, 83, 64, 36 + .short 89, 75, 50, 18 + .short 90, 87, 80, 70 + .short 57, 43, 25, 9 + .short 90, 90, 88, 85 + .short 82, 78, 73, 67 + .short 61, 54, 46, 38 + .short 31, 22, 13, 4 +endconst -function ff_hevc_idct_8x8_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - vdup.16 q8, r1 - vdup.16 q9, r1 - vmov.16 q10, q8 - vmov.16 q11, q8 - vmov.16 q12, q8 - vmov.16 q13, q8 - vmov.16 q14, q8 - vmov.16 q15, q8 - vstm r0, {q8-q15} - bx lr -endfunc - -function ff_hevc_idct_16x16_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - vdup.16 q8, r1 - vdup.16 q9, r1 - vmov.16 q10, q8 - vmov.16 q11, q8 - vmov.16 q12, q8 - vmov.16 q13, q8 - vmov.16 q14, q8 - vmov.16 q15, q8 - vstm r0!, {q8-q15} - vstm r0!, {q8-q15} - vstm r0!, {q8-q15} - vstm r0, {q8-q15} - bx lr -endfunc - -function ff_hevc_idct_32x32_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - mov r3, #16 - vdup.16 q8, r1 - vdup.16 q9, r1 - vmov.16 q10, q8 - vmov.16 q11, q8 - vmov.16 q12, q8 - vmov.16 q13, q8 - vmov.16 q14, q8 - vmov.16 q15, q8 -1: subs r3, #1 - vstm r0!, {q8-q15} - bne 1b - bx lr -endfunc - -function ff_hevc_add_residual_4x4_neon_8, export=1 - vldm r1, {q0-q1} - vld1.32 d4[0], [r0], r2 - vld1.32 d4[1], [r0], r2 - vld1.32 d5[0], [r0], r2 - vld1.32 d5[1], [r0], r2 - sub r0, r0, r2, lsl #2 - vmovl.u8 q8, d4 - vmovl.u8 q9, d5 - vqadd.s16 q0, q0, q8 - vqadd.s16 q1, q1, q9 - vqmovun.s16 d0, q0 - vqmovun.s16 d1, q1 - vst1.32 d0[0], [r0], r2 - vst1.32 d0[1], [r0], r2 - vst1.32 d1[0], [r0], r2 - vst1.32 d1[1], [r0], r2 - bx lr -endfunc - -function ff_hevc_add_residual_8x8_neon_8, export=1 - mov r3, #8 -1: subs r3, #1 - vld1.16 {q0}, [r1]! - vld1.8 d16, [r0] - vmovl.u8 q8, d16 - vqadd.s16 q0, q8 - vqmovun.s16 d0, q0 - vst1.32 d0, [r0], r2 - bne 1b - bx lr -endfunc - -function ff_hevc_add_residual_16x16_neon_8, export=1 - mov r3, #16 -1: subs r3, #1 - vld1.16 {q0, q1}, [r1]! - vld1.8 {q8}, [r0] - vmovl.u8 q9, d16 - vmovl.u8 q10, d17 - vqadd.s16 q0, q9 - vqadd.s16 q1, q10 - vqmovun.s16 d0, q0 - vqmovun.s16 d1, q1 - vst1.8 {q0}, [r0], r2 - bne 1b - bx lr -endfunc - -function ff_hevc_add_residual_32x32_neon_8, export=1 - mov r3, #32 -1: subs r3, #1 - vldm r1!, {q0-q3} - vld1.8 {q8, q9}, [r0] - vmovl.u8 q10, d16 - vmovl.u8 q11, d17 - vmovl.u8 q12, d18 - vmovl.u8 q13, d19 - vqadd.s16 q0, q10 - vqadd.s16 q1, q11 - vqadd.s16 q2, q12 - vqadd.s16 q3, q13 - vqmovun.s16 d0, q0 - vqmovun.s16 d1, q1 - vqmovun.s16 d2, q2 - vqmovun.s16 d3, q3 - vst1.8 {q0, q1}, [r0], r2 - bne 1b - bx lr -endfunc - -.macro transpose_16b_8x8 r0, r1, r2, r3, r4, r5, r6, r7 - vtrn.64 \r0, \r4 - vtrn.64 \r1, \r5 - vtrn.64 \r2, \r6 - vtrn.64 \r3, \r7 - vtrn.32 \r0, \r2 - vtrn.32 \r1, \r3 - vtrn.32 \r4, \r6 - vtrn.32 \r5, \r7 - vtrn.16 \r0, \r1 - vtrn.16 \r2, \r3 - vtrn.16 \r4, \r5 - vtrn.16 \r6, \r7 +.macro clip10 in1, in2, c1, c2 + vmax.s16 \in1, \in1, \c1 + vmax.s16 \in2, \in2, \c1 + vmin.s16 \in1, \in1, \c2 + vmin.s16 \in2, \in2, \c2 .endm -// in 4 q regs -// output 8 d regs -.macro transpose_16b_4x4 r0, r1, r2, r3 - vtrn.32 \r0, \r2 - vtrn.32 \r1, \r3 - vtrn.16 \r0, \r1 - vtrn.16 \r2, \r3 +function ff_hevc_add_residual_4x4_8_neon, export=1 + vld1.16 {q0-q1}, [r1, :128] + vld1.32 d4[0], [r0, :32], r2 + vld1.32 d4[1], [r0, :32], r2 + vld1.32 d5[0], [r0, :32], r2 + vld1.32 d5[1], [r0, :32], r2 + sub r0, r0, r2, lsl #2 + vmovl.u8 q8, d4 + vmovl.u8 q9, d5 + vqadd.s16 q0, q0, q8 + vqadd.s16 q1, q1, q9 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vst1.32 d0[0], [r0, :32], r2 + vst1.32 d0[1], [r0, :32], r2 + vst1.32 d1[0], [r0, :32], r2 + vst1.32 d1[1], [r0, :32], r2 + bx lr +endfunc + +function ff_hevc_add_residual_4x4_10_neon, export=1 + mov r12, r0 + vld1.16 {q0-q1}, [r1, :128] + vld1.16 d4, [r12, :64], r2 + vld1.16 d5, [r12, :64], r2 + vld1.16 d6, [r12, :64], r2 + vqadd.s16 q0, q2 + vld1.16 d7, [r12, :64], r2 + vmov.s16 q12, #0 + vqadd.s16 q1, q3 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF + clip10 q0, q1, q12, q13 + vst1.16 d0, [r0, :64], r2 + vst1.16 d1, [r0, :64], r2 + vst1.16 d2, [r0, :64], r2 + vst1.16 d3, [r0, :64], r2 + bx lr +endfunc + +function ff_hevc_add_residual_8x8_8_neon, export=1 + add r12, r0, r2 + add r2, r2, r2 + mov r3, #8 +1: subs r3, #2 + vld1.8 {d16}, [r0, :64] + vld1.8 {d17}, [r12, :64] + vmovl.u8 q9, d16 + vld1.16 {q0-q1}, [r1, :128]! + vmovl.u8 q8, d17 + vqadd.s16 q0, q9 + vqadd.s16 q1, q8 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vst1.8 d0, [r0, :64], r2 + vst1.8 d1, [r12, :64], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_8x8_10_neon, export=1 + add r12, r0, r2 + add r2, r2, r2 + mov r3, #8 + vmov.s16 q12, #0 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF +1: subs r3, #2 + vld1.16 {q0-q1}, [r1, :128]! + vld1.16 {q8}, [r0, :128] + vqadd.s16 q0, q8 + vld1.16 {q9}, [r12, :128] + vqadd.s16 q1, q9 + clip10 q0, q1, q12, q13 + vst1.16 {q0}, [r0, :128], r2 + vst1.16 {q1}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_16x16_8_neon, export=1 + mov r3, #16 + add r12, r0, r2 + add r2, r2, r2 +1: subs r3, #2 + vld1.8 {q8}, [r0, :128] + vld1.16 {q0, q1}, [r1, :128]! + vld1.8 {q11}, [r12, :128] + vld1.16 {q2, q3}, [r1, :128]! + vmovl.u8 q9, d16 + vmovl.u8 q10, d17 + vmovl.u8 q12, d22 + vmovl.u8 q13, d23 + vqadd.s16 q0, q9 + vqadd.s16 q1, q10 + vqadd.s16 q2, q12 + vqadd.s16 q3, q13 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vst1.8 {q0}, [r0, :128], r2 + vst1.8 {q1}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_16x16_10_neon, export=1 + mov r3, #16 + vmov.s16 q12, #0 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF + add r12, r0, r2 + add r2, r2, r2 +1: subs r3, #2 + vld1.16 {q8-q9}, [r0, :128] + vld1.16 {q0, q1}, [r1, :128]! + vqadd.s16 q0, q8 + vld1.16 {q10-q11}, [r12, :128] + vqadd.s16 q1, q9 + vld1.16 {q2, q3}, [r1, :128]! + vqadd.s16 q2, q10 + vqadd.s16 q3, q11 + clip10 q0, q1, q12, q13 + clip10 q2, q3, q12, q13 + vst1.16 {q0-q1}, [r0, :128], r2 + vst1.16 {q2-q3}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_32x32_8_neon, export=1 + vpush {q4-q7} + add r12, r0, r2 + add r2, r2, r2 + mov r3, #32 +1: subs r3, #2 + vld1.8 {q12, q13}, [r0, :128] + vmovl.u8 q8, d24 + vmovl.u8 q9, d25 + vld1.8 {q14, q15}, [r12, :128] + vmovl.u8 q10, d26 + vmovl.u8 q11, d27 + vmovl.u8 q12, d28 + vldm r1!, {q0-q7} + vmovl.u8 q13, d29 + vmovl.u8 q14, d30 + vmovl.u8 q15, d31 + vqadd.s16 q0, q8 + vqadd.s16 q1, q9 + vqadd.s16 q2, q10 + vqadd.s16 q3, q11 + vqadd.s16 q4, q12 + vqadd.s16 q5, q13 + vqadd.s16 q6, q14 + vqadd.s16 q7, q15 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vqmovun.s16 d4, q4 + vqmovun.s16 d5, q5 + vst1.8 {q0, q1}, [r0, :128], r2 + vqmovun.s16 d6, q6 + vqmovun.s16 d7, q7 + vst1.8 {q2, q3}, [r12, :128], r2 + bne 1b + vpop {q4-q7} + bx lr +endfunc + +function ff_hevc_add_residual_32x32_10_neon, export=1 + mov r3, #32 + add r12, r0, #32 + vmov.s16 q12, #0 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF +1: subs r3, #1 + vldm r1!, {q0-q3} + vld1.16 {q8, q9}, [r0, :128] + vld1.16 {q10, q11}, [r12, :128] + vqadd.s16 q0, q8 + vqadd.s16 q1, q9 + vqadd.s16 q2, q10 + vqadd.s16 q3, q11 + clip10 q0, q1, q12, q13 + clip10 q2, q3, q12, q13 + vst1.16 {q0-q1}, [r0, :128], r2 + vst1.16 {q2-q3}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +.macro idct_4x4_dc bitdepth +function ff_hevc_idct_4x4_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + vdup.16 q0, r1 + vdup.16 q1, r1 + vst1.16 {q0, q1}, [r0, :128] + bx lr +endfunc .endm +.macro idct_8x8_dc bitdepth +function ff_hevc_idct_8x8_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + vdup.16 q8, r1 + vdup.16 q9, r1 + vmov.16 q10, q8 + vmov.16 q11, q8 + vmov.16 q12, q8 + vmov.16 q13, q8 + vmov.16 q14, q8 + vmov.16 q15, q8 + vstm r0, {q8-q15} + bx lr +endfunc +.endm + +.macro idct_16x16_dc bitdepth +function ff_hevc_idct_16x16_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + vdup.16 q8, r1 + vdup.16 q9, r1 + vmov.16 q10, q8 + vmov.16 q11, q8 + vmov.16 q12, q8 + vmov.16 q13, q8 + vmov.16 q14, q8 + vmov.16 q15, q8 + vstm r0!, {q8-q15} + vstm r0!, {q8-q15} + vstm r0!, {q8-q15} + vstm r0, {q8-q15} + bx lr +endfunc +.endm + +.macro idct_32x32_dc bitdepth +function ff_hevc_idct_32x32_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + mov r3, #16 + vdup.16 q8, r1 + vdup.16 q9, r1 + vmov.16 q10, q8 + vmov.16 q11, q8 + vmov.16 q12, q8 + vmov.16 q13, q8 + vmov.16 q14, q8 + vmov.16 q15, q8 +1: subs r3, #1 + vstm r0!, {q8-q15} + bne 1b + bx lr +endfunc +.endm + +.macro sum_sub out, in, c, op + .ifc \op, + + vmlal.s16 \out, \in, \c + .else + vmlsl.s16 \out, \in, \c + .endif +.endm + +.macro tr_4x4 in0, in1, in2, in3, out0, out1, out2, out3, shift, tmp0, tmp1, tmp2, tmp3, tmp4 + vshll.s16 \tmp0, \in0, #6 + vmull.s16 \tmp2, \in1, d4[1] + vmov \tmp1, \tmp0 + vmull.s16 \tmp3, \in1, d4[3] + vmlal.s16 \tmp0, \in2, d4[0] @e0 + vmlsl.s16 \tmp1, \in2, d4[0] @e1 + vmlal.s16 \tmp2, \in3, d4[3] @o0 + vmlsl.s16 \tmp3, \in3, d4[1] @o1 + + vadd.s32 \tmp4, \tmp0, \tmp2 + vsub.s32 \tmp0, \tmp0, \tmp2 + vadd.s32 \tmp2, \tmp1, \tmp3 + vsub.s32 \tmp1, \tmp1, \tmp3 + vqrshrn.s32 \out0, \tmp4, #\shift + vqrshrn.s32 \out3, \tmp0, #\shift + vqrshrn.s32 \out1, \tmp2, #\shift + vqrshrn.s32 \out2, \tmp1, #\shift +.endm + +.macro tr_4x4_8 in0, in1, in2, in3, out0, out1, out2, out3, tmp0, tmp1, tmp2, tmp3 + vshll.s16 \tmp0, \in0, #6 + vld1.s16 {\in0}, [r1, :64]! + vmov \tmp1, \tmp0 + vmull.s16 \tmp2, \in1, \in0[1] + vmull.s16 \tmp3, \in1, \in0[3] + vmlal.s16 \tmp0, \in2, \in0[0] @e0 + vmlsl.s16 \tmp1, \in2, \in0[0] @e1 + vmlal.s16 \tmp2, \in3, \in0[3] @o0 + vmlsl.s16 \tmp3, \in3, \in0[1] @o1 + + vld1.s16 {\in0}, [r1, :64] + + vadd.s32 \out0, \tmp0, \tmp2 + vadd.s32 \out1, \tmp1, \tmp3 + vsub.s32 \out2, \tmp1, \tmp3 + vsub.s32 \out3, \tmp0, \tmp2 + + sub r1, r1, #8 +.endm + +@ Do a 4x4 transpose, using q registers for the subtransposes that don't +@ need to address the indiviudal d registers. +@ r0,r1 == rq0, r2,r3 == rq1 +.macro transpose_4x4 rq0, rq1, r0, r1, r2, r3 + vtrn.32 \rq0, \rq1 + vtrn.16 \r0, \r1 + vtrn.16 \r2, \r3 +.endm + +.macro idct_4x4 bitdepth +function ff_hevc_idct_4x4_\bitdepth\()_neon, export=1 +@r0 - coeffs + vld1.s16 {q0-q1}, [r0, :128] + + movrel r1, trans + vld1.s16 {d4}, [r1, :64] + + tr_4x4 d0, d1, d2, d3, d16, d17, d18, d19, 7, q10, q11, q12, q13, q0 + transpose_4x4 q8, q9, d16, d17, d18, d19 + + tr_4x4 d16, d17, d18, d19, d0, d1, d2, d3, 20 - \bitdepth, q10, q11, q12, q13, q0 + transpose_4x4 q0, q1, d0, d1, d2, d3 + vst1.s16 {d0-d3}, [r0, :128] + bx lr +endfunc +.endm + +.macro transpose8_4x4 r0, r1, r2, r3 + vtrn.16 \r0, \r1 + vtrn.16 \r2, \r3 + vtrn.32 \r0, \r2 + vtrn.32 \r1, \r3 +.endm + +.macro transpose_8x8 r0, r1, r2, r3, r4, r5, r6, r7, l0, l1, l2, l3, l4, l5, l6, l7 + transpose8_4x4 \r0, \r1, \r2, \r3 + transpose8_4x4 \r4, \r5, \r6, \r7 + + transpose8_4x4 \l0, \l1, \l2, \l3 + transpose8_4x4 \l4, \l5, \l6, \l7 +.endm + +.macro tr_8x4 shift, in0, in1, in2, in3, in4, in5, in6, in7 + tr_4x4_8 \in0, \in2, \in4, \in6, q8, q9, q10, q11, q12, q13, q14, q15 + + vmull.s16 q14, \in1, \in0[2] + vmull.s16 q12, \in1, \in0[0] + vmull.s16 q13, \in1, \in0[1] + sum_sub q14, \in3, \in0[0], - + sum_sub q12, \in3, \in0[1], + + sum_sub q13, \in3, \in0[3], - + + sum_sub q14, \in5, \in0[3], + + sum_sub q12, \in5, \in0[2], + + sum_sub q13, \in5, \in0[0], - + + sum_sub q14, \in7, \in0[1], + + sum_sub q12, \in7, \in0[3], + + sum_sub q13, \in7, \in0[2], - + + vadd.s32 q15, q10, q14 + vsub.s32 q10, q10, q14 + vqrshrn.s32 \in2, q15, \shift + + vmull.s16 q15, \in1, \in0[3] + sum_sub q15, \in3, \in0[2], - + sum_sub q15, \in5, \in0[1], + + sum_sub q15, \in7, \in0[0], - + + vqrshrn.s32 \in5, q10, \shift + + vadd.s32 q10, q8, q12 + vsub.s32 q8, q8, q12 + vadd.s32 q12, q9, q13 + vsub.s32 q9, q9, q13 + vadd.s32 q14, q11, q15 + vsub.s32 q11, q11, q15 + + vqrshrn.s32 \in0, q10, \shift + vqrshrn.s32 \in7, q8, \shift + vqrshrn.s32 \in1, q12, \shift + vqrshrn.s32 \in6, q9, \shift + vqrshrn.s32 \in3, q14, \shift + vqrshrn.s32 \in4, q11, \shift +.endm + +.macro idct_8x8 bitdepth +function ff_hevc_idct_8x8_\bitdepth\()_neon, export=1 +@r0 - coeffs + vpush {q4-q7} + + mov r1, r0 + mov r2, #64 + add r3, r0, #32 + vld1.s16 {q0-q1}, [r1,:128], r2 + vld1.s16 {q2-q3}, [r3,:128], r2 + vld1.s16 {q4-q5}, [r1,:128], r2 + vld1.s16 {q6-q7}, [r3,:128], r2 + + movrel r1, trans + + tr_8x4 7, d0, d2, d4, d6, d8, d10, d12, d14 + tr_8x4 7, d1, d3, d5, d7, d9, d11, d13, d15 + + @ Transpose each 4x4 block, and swap how d4-d7 and d8-d11 are used. + @ Layout before: + @ d0 d1 + @ d2 d3 + @ d4 d5 + @ d6 d7 + @ d8 d9 + @ d10 d11 + @ d12 d13 + @ d14 d15 + transpose_8x8 d0, d2, d4, d6, d8, d10, d12, d14, d1, d3, d5, d7, d9, d11, d13, d15 + @ Now the layout is: + @ d0 d8 + @ d2 d10 + @ d4 d12 + @ d6 d14 + @ d1 d9 + @ d3 d11 + @ d5 d13 + @ d7 d15 + + tr_8x4 20 - \bitdepth, d0, d2, d4, d6, d1, d3, d5, d7 + vswp d0, d8 + tr_8x4 20 - \bitdepth, d0, d10, d12, d14, d9, d11, d13, d15 + vswp d0, d8 + + transpose_8x8 d0, d2, d4, d6, d8, d10, d12, d14, d1, d3, d5, d7, d9, d11, d13, d15 + + mov r1, r0 + mov r2, #64 + add r3, r0, #32 + vst1.s16 {q0-q1}, [r1,:128], r2 + vst1.s16 {q2-q3}, [r3,:128], r2 + vst1.s16 {q4-q5}, [r1,:128], r2 + vst1.s16 {q6-q7}, [r3,:128], r2 + + vpop {q4-q7} + bx lr +endfunc +.endm + +.macro butterfly e, o, tmp_p, tmp_m + vadd.s32 \tmp_p, \e, \o + vsub.s32 \tmp_m, \e, \o +.endm + +.macro tr16_8x4 in0, in1, in2, in3, in4, in5, in6, in7, offset + tr_4x4_8 \in0, \in2, \in4, \in6, q8, q9, q10, q11, q12, q13, q14, q15 + + vmull.s16 q12, \in1, \in0[0] + vmull.s16 q13, \in1, \in0[1] + vmull.s16 q14, \in1, \in0[2] + vmull.s16 q15, \in1, \in0[3] + sum_sub q12, \in3, \in0[1], + + sum_sub q13, \in3, \in0[3], - + sum_sub q14, \in3, \in0[0], - + sum_sub q15, \in3, \in0[2], - + + sum_sub q12, \in5, \in0[2], + + sum_sub q13, \in5, \in0[0], - + sum_sub q14, \in5, \in0[3], + + sum_sub q15, \in5, \in0[1], + + + sum_sub q12, \in7, \in0[3], + + sum_sub q13, \in7, \in0[2], - + sum_sub q14, \in7, \in0[1], + + sum_sub q15, \in7, \in0[0], - + + butterfly q8, q12, q0, q7 + butterfly q9, q13, q1, q6 + butterfly q10, q14, q2, q5 + butterfly q11, q15, q3, q4 + add r4, sp, #\offset + vst1.s32 {q0-q1}, [r4, :128]! + vst1.s32 {q2-q3}, [r4, :128]! + vst1.s32 {q4-q5}, [r4, :128]! + vst1.s32 {q6-q7}, [r4, :128] +.endm + +.macro load16 in0, in1, in2, in3, in4, in5, in6, in7 + vld1.s16 {\in0}, [r1, :64], r2 + vld1.s16 {\in1}, [r3, :64], r2 + vld1.s16 {\in2}, [r1, :64], r2 + vld1.s16 {\in3}, [r3, :64], r2 + vld1.s16 {\in4}, [r1, :64], r2 + vld1.s16 {\in5}, [r3, :64], r2 + vld1.s16 {\in6}, [r1, :64], r2 + vld1.s16 {\in7}, [r3, :64], r2 +.endm + +.macro add_member in, t0, t1, t2, t3, t4, t5, t6, t7, op0, op1, op2, op3, op4, op5, op6, op7 + sum_sub q5, \in, \t0, \op0 + sum_sub q6, \in, \t1, \op1 + sum_sub q7, \in, \t2, \op2 + sum_sub q8, \in, \t3, \op3 + sum_sub q9, \in, \t4, \op4 + sum_sub q10, \in, \t5, \op5 + sum_sub q11, \in, \t6, \op6 + sum_sub q12, \in, \t7, \op7 +.endm + +.macro butterfly16 in0, in1, in2, in3, in4, in5, in6, in7 + vadd.s32 q4, \in0, \in1 + vsub.s32 \in0, \in0, \in1 + vadd.s32 \in1, \in2, \in3 + vsub.s32 \in2, \in2, \in3 + vadd.s32 \in3, \in4, \in5 + vsub.s32 \in4, \in4, \in5 + vadd.s32 \in5, \in6, \in7 + vsub.s32 \in6, \in6, \in7 +.endm + +.macro store16 in0, in1, in2, in3, in4, in5, in6, in7, rx + vst1.s16 \in0, [r1, :64], r2 + vst1.s16 \in1, [r3, :64], \rx + vst1.s16 \in2, [r1, :64], r2 + vst1.s16 \in3, [r3, :64], \rx + vst1.s16 \in4, [r1, :64], r2 + vst1.s16 \in5, [r3, :64], \rx + vst1.s16 \in6, [r1, :64], r2 + vst1.s16 \in7, [r3, :64], \rx +.endm + +.macro scale out0, out1, out2, out3, out4, out5, out6, out7, in0, in1, in2, in3, in4, in5, in6, in7, shift + vqrshrn.s32 \out0, \in0, \shift + vqrshrn.s32 \out1, \in1, \shift + vqrshrn.s32 \out2, \in2, \shift + vqrshrn.s32 \out3, \in3, \shift + vqrshrn.s32 \out4, \in4, \shift + vqrshrn.s32 \out5, \in5, \shift + vqrshrn.s32 \out6, \in6, \shift + vqrshrn.s32 \out7, \in7, \shift +.endm + +@stores in1, in2, in4, in6 ascending from off1 and +@stores in1, in3, in5, in7 descending from off2 +.macro store_to_stack off1, off2, in0, in2, in4, in6, in7, in5, in3, in1 + add r1, sp, #\off1 + add r3, sp, #\off2 + mov r2, #-16 + vst1.s32 {\in0}, [r1, :128]! + vst1.s32 {\in1}, [r3, :128], r2 + vst1.s32 {\in2}, [r1, :128]! + vst1.s32 {\in3}, [r3, :128], r2 + vst1.s32 {\in4}, [r1, :128]! + vst1.s32 {\in5}, [r3, :128], r2 + vst1.s32 {\in6}, [r1, :128] + vst1.s32 {\in7}, [r3, :128] +.endm + +.macro tr_16x4 name, shift, offset, step +function func_tr_16x4_\name + mov r1, r5 + add r3, r5, #(\step * 64) + mov r2, #(\step * 128) + load16 d0, d1, d2, d3, d4, d5, d6, d7 + movrel r1, trans + + tr16_8x4 d0, d1, d2, d3, d4, d5, d6, d7, \offset + + add r1, r5, #(\step * 32) + add r3, r5, #(\step * 3 *32) + mov r2, #(\step * 128) + load16 d8, d9, d2, d3, d4, d5, d6, d7 + movrel r1, trans + 16 + vld1.s16 {q0}, [r1, :128] + vmull.s16 q5, d8, d0[0] + vmull.s16 q6, d8, d0[1] + vmull.s16 q7, d8, d0[2] + vmull.s16 q8, d8, d0[3] + vmull.s16 q9, d8, d1[0] + vmull.s16 q10, d8, d1[1] + vmull.s16 q11, d8, d1[2] + vmull.s16 q12, d8, d1[3] + + add_member d9, d0[1], d1[0], d1[3], d1[1], d0[2], d0[0], d0[3], d1[2], +, +, +, -, -, -, -, - + add_member d2, d0[2], d1[3], d0[3], d0[1], d1[2], d1[0], d0[0], d1[1], +, +, -, -, -, +, +, + + add_member d3, d0[3], d1[1], d0[1], d1[3], d0[0], d1[2], d0[2], d1[0], +, -, -, +, +, +, -, - + add_member d4, d1[0], d0[2], d1[2], d0[0], d1[3], d0[1], d1[1], d0[3], +, -, -, +, -, -, +, + + add_member d5, d1[1], d0[0], d1[0], d1[2], d0[1], d0[3], d1[3], d0[2], +, -, +, +, -, +, +, - + add_member d6, d1[2], d0[3], d0[0], d0[2], d1[1], d1[3], d1[0], d0[1], +, -, +, -, +, +, -, + + add_member d7, d1[3], d1[2], d1[1], d1[0], d0[3], d0[2], d0[1], d0[0], +, -, +, -, +, -, +, - + + add r4, sp, #\offset + vld1.s32 {q0-q1}, [r4, :128]! + vld1.s32 {q2-q3}, [r4, :128]! + + butterfly16 q0, q5, q1, q6, q2, q7, q3, q8 + .if \shift > 0 + scale d26, d27, d28, d29, d30, d31, d16, d17, q4, q0, q5, q1, q6, q2, q7, q3, \shift + transpose8_4x4 d26, d28, d30, d16 + transpose8_4x4 d17, d31, d29, d27 + mov r1, r6 + add r3, r6, #(24 +3*32) + mov r2, #32 + mov r4, #-32 + store16 d26, d27, d28, d29, d30, d31, d16, d17, r4 + .else + store_to_stack \offset, (\offset + 240), q4, q5, q6, q7, q3, q2, q1, q0 + .endif + + add r4, sp, #(\offset + 64) + vld1.s32 {q0-q1}, [r4, :128]! + vld1.s32 {q2-q3}, [r4, :128] + butterfly16 q0, q9, q1, q10, q2, q11, q3, q12 + .if \shift > 0 + scale d26, d27, d28, d29, d30, d31, d8, d9, q4, q0, q9, q1, q10, q2, q11, q3, \shift + transpose8_4x4 d26, d28, d30, d8 + transpose8_4x4 d9, d31, d29, d27 + + add r1, r6, #8 + add r3, r6, #(16 + 3 * 32) + mov r2, #32 + mov r4, #-32 + store16 d26, d27, d28, d29, d30, d31, d8, d9, r4 + .else + store_to_stack (\offset + 64), (\offset + 176), q4, q9, q10, q11, q3, q2, q1, q0 + .endif + + bx lr +endfunc +.endm + +.macro idct_16x16 bitdepth +function ff_hevc_idct_16x16_\bitdepth\()_neon, export=1 +@r0 - coeffs + push {r4-r7, lr} + vpush {q4-q7} + + @ Align the stack, allocate a temp buffer +T mov r7, sp +T and r7, r7, #15 +A and r7, sp, #15 + add r7, r7, #640 + sub sp, sp, r7 + +.irp i, 0, 1, 2, 3 + add r5, r0, #(8 * \i) + add r6, sp, #(8 * \i * 16) + bl func_tr_16x4_firstpass +.endr + +.irp i, 0, 1, 2, 3 + add r5, sp, #(8 * \i) + add r6, r0, #(8 * \i * 16) + bl func_tr_16x4_secondpass_\bitdepth +.endr + + add sp, sp, r7 + + vpop {q4-q7} + pop {r4-r7, pc} +endfunc +.endm + +.macro load32 + add r1, r5, #64 + add r3, r1, #128 + mov r2, #256 + vld1.s16 {d4}, [r1, :64], r2 + vld1.s16 {d5}, [r3, :64], r2 + vld1.s16 {d6}, [r1, :64], r2 + vld1.s16 {d7}, [r3, :64], r2 + vld1.s16 {d8}, [r1, :64], r2 + vld1.s16 {d9}, [r3, :64], r2 + vld1.s16 {d10}, [r1, :64], r2 + vld1.s16 {d11}, [r3, :64], r2 + vld1.s16 {d12}, [r1, :64], r2 + vld1.s16 {d13}, [r3, :64], r2 + vld1.s16 {d14}, [r1, :64], r2 + vld1.s16 {d15}, [r3, :64], r2 + vld1.s16 {d16}, [r1, :64], r2 + vld1.s16 {d17}, [r3, :64], r2 + vld1.s16 {d18}, [r1, :64], r2 + vld1.s16 {d19}, [r3, :64], r2 +.endm + +.macro add_member32 in, t0, t1, t2, t3, op0, op1, op2, op3 + sum_sub q10, \in, \t0, \op0 + sum_sub q11, \in, \t1, \op1 + sum_sub q12, \in, \t2, \op2 + sum_sub q13, \in, \t3, \op3 +.endm + +.macro butterfly32 in0, in1, in2, in3 + vadd.s32 q1, \in0, \in1 + vsub.s32 \in0, \in0, \in1 + vadd.s32 \in1, \in2, \in3 + vsub.s32 \in2, \in2, \in3 +.endm + +.macro scale32 out0, out1, out2, out3, in0, in1, in2, in3, shift + vqrshrn.s32 \out0, \in0, \shift + vqrshrn.s32 \out1, \in1, \shift + vqrshrn.s32 \out2, \in2, \shift + vqrshrn.s32 \out3, \in3, \shift +.endm + +.macro multiply in + vmull.s16 q10, d4, \in[0] + vmull.s16 q11, d4, \in[1] + vmull.s16 q12, d4, \in[2] + vmull.s16 q13, d4, \in[3] +.endm + +.macro scale_store shift + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q10, q15, q11 + scale32 d22, d23, d20, d21, q1, q14, q10, q15, \shift + + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q12, q15, q13 + scale32 d2, d3, d28, d29, q1, q14, q12, q15, \shift + transpose8_4x4 d22, d20, d2, d28 + transpose8_4x4 d29, d3, d21, d23 + store16 d22, d23, d20, d21, d2, d3, d28, d29, r8 + + @ reload multiplication coefficiens to q1 + vld1.s16 {q1}, [r9, :128] +.endm + +function tr_block1 + multiply d0 + add_member32 d5, d0[1], d1[0], d1[3], d2[2], +, +, +, + + add_member32 d6, d0[2], d1[3], d3[0], d3[2], +, +, +, - + add_member32 d7, d0[3], d2[2], d3[2], d1[3], +, +, -, - + add_member32 d8, d1[0], d3[1], d2[1], d0[0], +, +, -, - + add_member32 d9, d1[1], d3[3], d1[0], d1[2], +, -, -, - + add_member32 d10, d1[2], d3[0], d0[0], d3[1], +, -, -, - + add_member32 d11, d1[3], d2[1], d1[1], d2[3], +, -, -, + + add_member32 d12, d2[0], d1[2], d2[2], d1[0], +, -, -, + + add_member32 d13, d2[1], d0[3], d3[3], d0[2], +, -, -, + + add_member32 d14, d2[2], d0[1], d2[3], d2[1], +, -, +, + + add_member32 d15, d2[3], d0[2], d1[2], d3[3], +, -, +, - + add_member32 d16, d3[0], d1[1], d0[1], d2[0], +, -, +, - + add_member32 d17, d3[1], d2[0], d0[3], d0[1], +, -, +, - + add_member32 d18, d3[2], d2[3], d2[0], d1[1], +, -, +, - + add_member32 d19, d3[3], d3[2], d3[1], d3[0], +, -, +, - + bx lr +endfunc + +function tr_block2 + multiply d1 + add_member32 d5, d3[1], d3[3], d3[0], d2[1], +, -, -, - + add_member32 d6, d2[1], d1[0], d0[0], d1[1], -, -, -, - + add_member32 d7, d0[0], d1[2], d3[1], d2[3], -, -, -, + + add_member32 d8, d2[0], d3[2], d1[1], d0[3], -, +, +, + + add_member32 d9, d3[2], d0[3], d1[3], d3[1], +, +, +, - + add_member32 d10, d1[1], d1[3], d2[3], d0[0], +, +, -, - + add_member32 d11, d0[3], d3[1], d0[1], d3[3], +, -, -, + + add_member32 d12, d3[0], d0[2], d3[2], d0[1], +, -, -, + + add_member32 d13, d2[2], d2[0], d1[0], d3[2], -, -, +, + + add_member32 d14, d0[1], d3[0], d2[0], d0[2], -, +, +, - + add_member32 d15, d1[3], d0[1], d2[2], d3[0], -, +, -, - + add_member32 d16, d3[3], d2[1], d0[2], d1[0], +, +, -, + + add_member32 d17, d1[2], d2[3], d3[3], d2[2], +, -, -, + + add_member32 d18, d0[2], d0[1], d0[3], d1[2], +, -, +, - + add_member32 d19, d2[3], d2[2], d2[1], d2[0], +, -, +, - + bx lr +endfunc + +function tr_block3 + multiply d2 + add_member32 d5, d1[2], d0[3], d0[0], d0[2], -, -, -, - + add_member32 d6, d2[2], d3[3], d2[3], d1[2], -, -, +, + + add_member32 d7, d1[0], d0[2], d2[1], d3[3], +, +, +, - + add_member32 d8, d3[0], d2[2], d0[1], d1[3], +, -, -, - + add_member32 d9, d0[2], d2[0], d3[0], d0[0], -, -, +, + + add_member32 d10, d3[2], d1[0], d2[0], d2[2], -, +, +, - + add_member32 d11, d0[0], d3[2], d0[2], d3[0], +, +, -, - + add_member32 d12, d3[3], d0[1], d3[1], d0[3], -, -, +, + + add_member32 d13, d0[1], d2[3], d1[3], d1[1], -, +, +, - + add_member32 d14, d3[1], d1[3], d0[3], d3[2], +, +, -, + + add_member32 d15, d0[3], d1[1], d3[2], d2[0], +, -, +, + + add_member32 d16, d2[3], d3[1], d1[2], d0[1], -, -, +, - + add_member32 d17, d1[1], d0[0], d1[0], d2[1], -, +, -, + + add_member32 d18, d2[1], d3[0], d3[3], d3[1], +, -, +, + + add_member32 d19, d1[3], d1[2], d1[1], d1[0], +, -, +, - + bx lr +endfunc + +function tr_block4 + multiply d3 + add_member32 d5, d1[1], d2[0], d2[3], d3[2], -, -, -, - + add_member32 d6, d0[0], d0[3], d2[0], d3[1], +, +, +, + + add_member32 d7, d2[0], d0[0], d1[1], d3[0], -, -, -, - + add_member32 d8, d3[3], d1[2], d0[2], d2[3], +, +, +, + + add_member32 d9, d2[1], d2[3], d0[0], d2[2], +, -, -, - + add_member32 d10, d0[2], d3[3], d0[3], d2[1], -, -, +, + + add_member32 d11, d1[0], d2[2], d1[2], d2[0], +, +, -, - + add_member32 d12, d2[3], d1[1], d2[1], d1[3], -, -, +, + + add_member32 d13, d3[1], d0[1], d3[0], d1[2], -, +, -, - + add_member32 d14, d1[2], d1[0], d3[3], d1[1], +, -, +, + + add_member32 d15, d0[1], d2[1], d3[1], d1[0], -, +, +, - + add_member32 d16, d1[3], d3[2], d2[2], d0[3], +, -, -, + + add_member32 d17, d3[2], d3[0], d1[3], d0[2], -, -, +, - + add_member32 d18, d2[2], d1[3], d1[0], d0[1], -, +, -, + + add_member32 d19, d0[3], d0[2], d0[1], d0[0], +, -, +, - + bx lr +endfunc + +.macro tr_32x4 name, shift +function func_tr_32x4_\name + mov r10, lr + bl func_tr_16x4_noscale + + load32 + movrel r9, trans + 32 + vld1.s16 {q0}, [r9, :128]! + vld1.s16 {q1}, [r9, :128] + + bl tr_block1 + + add r4, sp, #2048 + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q10, q15, q11 + scale32 d22, d23, d20, d21, q1, q14, q10, q15, \shift + + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q12, q15, q13 + scale32 d2, d3, d28, d29, q1, q14, q12, q15, \shift + + transpose8_4x4 d22, d20, d2, d28 + transpose8_4x4 d29, d3, d21, d23 + mov r1, r11 + mov r2, #64 + mov r8, #-64 + add r3, r11, #(56 + 3 * 64) + store16 d22, d23, d20, d21, d2, d3, d28, d29, r8 + + @ reload multiplication coefficiens to q1 + vld1.s16 {q1}, [r9, :128] + + bl tr_block2 + add r1, r11, #8 + add r3, r11, #(48 + 3 * 64) + mov r2, #64 + mov r8, #-64 + scale_store \shift + + bl tr_block3 + add r1, r11, #16 + add r3, r11, #(40 + 3 * 64) + mov r2, #64 + mov r8, #-64 + scale_store \shift + + bl tr_block4 + add r1, r11, #24 + add r3, r11, #(32 + 3 * 64) + mov r2, #64 + mov r8, #-64 + scale_store \shift + + bx r10 +endfunc +.endm + +.macro idct_32x32 bitdepth +function ff_hevc_idct_32x32_\bitdepth\()_neon, export=1 +@r0 - coeffs + push {r4-r11, lr} + vpush {q4-q7} + + @ Align the stack, allocate a temp buffer +T mov r7, sp +T and r7, r7, #15 +A and r7, sp, #15 + add r7, r7, #2432 + sub sp, sp, r7 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + add r5, r0, #(8 * \i) + add r11, sp, #(8 * \i * 32) + bl func_tr_32x4_firstpass +.endr + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + add r5, sp, #(8 * \i) + add r11, r0, #(8 * \i * 32) + bl func_tr_32x4_secondpass_\bitdepth +.endr + + add sp, sp, r7 + vpop {q4-q7} + pop {r4-r11, pc} +endfunc +.endm + +tr_16x4 firstpass, 7, 512, 1 +tr_16x4 secondpass_8, 20 - 8, 512, 1 +tr_16x4 secondpass_10, 20 - 10, 512, 1 +tr_16x4 noscale, 0, 2048, 4 +.ltorg +tr_32x4 firstpass, 7 +tr_32x4 secondpass_8, 20 - 8 +tr_32x4 secondpass_10, 20 - 10 +.ltorg + +idct_4x4 8 +idct_4x4_dc 8 +idct_4x4 10 +idct_4x4_dc 10 +idct_8x8 8 +idct_8x8_dc 8 +idct_8x8 10 +idct_8x8_dc 10 +idct_16x16 8 +idct_16x16_dc 8 +idct_16x16 10 +idct_16x16_dc 10 +idct_32x32 8 +idct_32x32_dc 8 +idct_32x32 10 +idct_32x32_dc 10 + /* uses registers q2 - q9 for temp values */ /* TODO: reorder */ .macro tr4_luma_shift r0, r1, r2, r3, shift @@ -225,67 +1015,7 @@ endfunc vqrshrn.s32 \r3, q5, \shift .endm -/* uses registers q2 - q6 for temp values */ -.macro tr4 r0, r1, r2, r3 - vmull.s16 q4, \r1, d0[0] // 83 * src1 - vmull.s16 q6, \r1, d0[1] // 36 * src1 - vshll.s16 q2, \r0, #6 // 64 * src0 - vshll.s16 q3, \r2, #6 // 64 * src2 - vadd.s32 q5, q2, q3 // 64 * (src0 + src2) e0 - vsub.s32 q2, q2, q3 // 64 * (src0 - src2) e1 - vmlal.s16 q4, \r3, d0[1] // 83 * src1 + 36 * src3 o0 - vmlsl.s16 q6, \r3, d0[0] // 36 * src1 - 83 * src3 o1 - - vsub.s32 q3, q5, q4 // e0 - o0 - vadd.s32 q4, q5, q4 // e0 + o0 - vadd.s32 q5, q2, q6 // e1 + o1 - vsub.s32 q6, q2, q6 // e1 - o1 -.endm - -.macro tr4_shift r0, r1, r2, r3, shift - vmull.s16 q4, \r1, d0[0] // 83 * src1 - vmull.s16 q6, \r1, d0[1] // 36 * src1 - vshll.s16 q2, \r0, #6 // 64 * src0 - vshll.s16 q3, \r2, #6 // 64 * src2 - vadd.s32 q5, q2, q3 // 64 * (src0 + src2) e0 - vsub.s32 q2, q2, q3 // 64 * (src0 - src2) e1 - vmlal.s16 q4, \r3, d0[1] // 83 * src1 + 36 * src3 o0 - vmlsl.s16 q6, \r3, d0[0] // 36 * src1 - 83 * src3 o1 - - vsub.s32 q3, q5, q4 // e0 - o0 - vadd.s32 q4, q5, q4 // e0 + o0 - vadd.s32 q5, q2, q6 // e1 + o1 - vsub.s32 q6, q2, q6 // e1 - o1 - - vqrshrn.s32 \r0, q4, \shift - vqrshrn.s32 \r1, q5, \shift - vqrshrn.s32 \r2, q6, \shift - vqrshrn.s32 \r3, q3, \shift -.endm - -function ff_hevc_transform_4x4_neon_8, export=1 - vpush {d8-d15} - vld1.16 {q14, q15}, [r0] // coeffs - ldr r3, =0x00240053 // 36 and 83 - vmov.32 d0[0], r3 - - tr4_shift d28, d29, d30, d31, #7 - - vtrn.16 d28, d29 - vtrn.16 d30, d31 - vtrn.32 q14, q15 - - tr4_shift d28, d29, d30, d31, #12 - - vtrn.16 d28, d29 - vtrn.16 d30, d31 - vtrn.32 q14, q15 - - vst1.16 {q14, q15}, [r0] - vpop {d8-d15} - bx lr -endfunc - +.ltorg function ff_hevc_transform_luma_4x4_neon_8, export=1 vpush {d8-d15} vld1.16 {q14, q15}, [r0] // coeffs @@ -311,155 +1041,3 @@ function ff_hevc_transform_luma_4x4_neon_8, export=1 vpop {d8-d15} bx lr endfunc - -.macro tr8_begin in0, in1, in2, in3 - vmull.s16 q7, \in0, d1[1] // 89 * src1 - vmull.s16 q8, \in0, d1[0] // 75 * src1 - vmull.s16 q9, \in0, d1[3] // 50 * src1 - vmull.s16 q10, \in0, d1[2] // 18 * src1 - - vmlal.s16 q7, \in1, d1[0] // 75 * src3 - vmlsl.s16 q8, \in1, d1[2] //-18 * src3 - vmlsl.s16 q9, \in1, d1[1] //-89 * src3 - vmlsl.s16 q10, \in1, d1[3] //-50 * src3 - - vmlal.s16 q7, \in2, d1[3] // 50 * src5 - vmlsl.s16 q8, \in2, d1[1] //-89 * src5 - vmlal.s16 q9, \in2, d1[2] // 18 * src5 - vmlal.s16 q10, \in2, d1[0] // 75 * src5 - - vmlal.s16 q7, \in3, d1[2] // 18 * src7 - vmlsl.s16 q8, \in3, d1[3] //-50 * src7 - vmlal.s16 q9, \in3, d1[0] // 75 * src7 - vmlsl.s16 q10, \in3, d1[1] //-89 * src7 -.endm - -.macro tr8_end shift - vadd.s32 q1, q4, q7 // e_8[0] + o_8[0], dst[0] - vsub.s32 q4, q4, q7 // e_8[0] - o_8[0], dst[7] - - vadd.s32 q2, q5, q8 // e_8[1] + o_8[1], dst[1] - vsub.s32 q5, q5, q8 // e_8[1] - o_8[1], dst[6] - - vadd.s32 q11, q6, q9 // e_8[2] + o_8[2], dst[2] - vsub.s32 q6, q6, q9 // e_8[2] - o_8[2], dst[5] - - vadd.s32 q12, q3, q10 // e_8[3] + o_8[3], dst[3] - vsub.s32 q3, q3, q10 // e_8[3] - o_8[3], dst[4] - vqrshrn.s32 d2, q1, \shift - vqrshrn.s32 d3, q2, \shift - vqrshrn.s32 d4, q11, \shift - vqrshrn.s32 d5, q12, \shift - vqrshrn.s32 d6, q3, \shift - vqrshrn.s32 d7, q6, \shift - vqrshrn.s32 d9, q4, \shift - vqrshrn.s32 d8, q5, \shift -.endm - -function ff_hevc_transform_8x8_neon_8, export=1 - push {r4-r8} - vpush {d8-d15} - mov r5, #16 - - adr r3, tr4f - vld1.16 {d0, d1}, [r3] - - // left half - vld1.16 {d24}, [r0], r5 - vld1.16 {d25}, [r0], r5 - vld1.16 {d26}, [r0], r5 - vld1.16 {d27}, [r0], r5 - vld1.16 {d28}, [r0], r5 - vld1.16 {d29}, [r0], r5 - vld1.16 {d30}, [r0], r5 - vld1.16 {d31}, [r0], r5 - sub r0, #128 - tr8_begin d25, d27, d29, d31 - tr4 d24, d26, d28, d30 - tr8_end #7 - vst1.16 {d2}, [r0], r5 - vst1.16 {d3}, [r0], r5 - vst1.16 {d4}, [r0], r5 - vst1.16 {d5}, [r0], r5 - vst1.16 {d6}, [r0], r5 - vst1.16 {d7}, [r0], r5 - vst1.16 {d8}, [r0], r5 - vst1.16 {d9}, [r0], r5 - sub r0, #128 - //skip right half if col_limit in r1 is less than 4 - cmp r1, #4 - blt 1f - //right half - add r0, #8 - vld1.16 {d24}, [r0], r5 - vld1.16 {d25}, [r0], r5 - vld1.16 {d26}, [r0], r5 - vld1.16 {d27}, [r0], r5 - vld1.16 {d28}, [r0], r5 - vld1.16 {d29}, [r0], r5 - vld1.16 {d30}, [r0], r5 - vld1.16 {d31}, [r0], r5 - sub r0, #128 - tr8_begin d25, d27, d29, d31 - tr4 d24, d26, d28, d30 - tr8_end #7 - vst1.16 {d2}, [r0], r5 - vst1.16 {d3}, [r0], r5 - vst1.16 {d4}, [r0], r5 - vst1.16 {d5}, [r0], r5 - vst1.16 {d6}, [r0], r5 - vst1.16 {d7}, [r0], r5 - vst1.16 {d8}, [r0], r5 - vst1.16 {d9}, [r0], r5 - sub r0, #136 -1: - // top half - vldm r0, {q12-q15} // coeffs - transpose_16b_4x4 d24, d26, d28, d30 - transpose_16b_4x4 d25, d27, d29, d31 - tr8_begin d26, d30, d27, d31 - tr4 d24, d28, d25, d29 - tr8_end #12 - transpose_16b_4x4 d2, d3, d4, d5 - transpose_16b_4x4 d6, d7, d8, d9 - vswp d7, d5 - vswp d7, d8 - vswp d3, d6 - vswp d6, d4 - vstm r0!, {q1-q4} - - // bottom half - vldm r0, {q12-q15} // coeffs - transpose_16b_4x4 d24, d26, d28, d30 - transpose_16b_4x4 d25, d27, d29, d31 - tr8_begin d26, d30, d27, d31 - tr4 d24, d28, d25, d29 - tr8_end #12 - transpose_16b_4x4 d2, d3, d4, d5 - transpose_16b_4x4 d6, d7, d8, d9 - vswp d7, d5 - vswp d7, d8 - vswp d3, d6 - vswp d6, d4 - //vstm r0, {q1-q4} - vst1.16 {q1-q2}, [r0] - add r0, #32 - vst1.16 {q3-q4}, [r0] - sub r0, #32 - vpop {d8-d15} - pop {r4-r8} - bx lr -endfunc - -.align 4 -tr4f: -.word 0x00240053 // 36 and d1[0] = 83 -.word 0x00000000 -tr8f: -.word 0x0059004b // 89, d0[0] = 75 -.word 0x00320012 // 50, d0[2] = 18 -tr16: -.word 0x005a0057 // 90, d2[0] = 87 -.word 0x00500046 // 80, d2[2] = 70 -.word 0x0039002b // 57, d2[0] = 43 -.word 0x00190009 // 25, d2[2] = 9 diff --git a/libavcodec/arm/hevcdsp_init_arm.c b/libavcodec/arm/hevcdsp_init_arm.c index adcc45451..e8fa1f79a 100644 --- a/libavcodec/arm/hevcdsp_init_arm.c +++ b/libavcodec/arm/hevcdsp_init_arm.c @@ -19,14 +19,16 @@ */ #include "libavutil/attributes.h" +#include "libavutil/cpu.h" #include "libavutil/arm/cpu.h" + #include "libavcodec/hevcdsp.h" #include "hevcdsp_arm.h" -av_cold void ff_hevcdsp_init_arm(HEVCDSPContext *c, const int bit_depth) +av_cold void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth) { int cpu_flags = av_get_cpu_flags(); if (have_neon(cpu_flags)) - ff_hevcdsp_init_neon(c, bit_depth); + ff_hevc_dsp_init_neon(c, bit_depth); } diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c index 1a3912c60..a4628d2a9 100644 --- a/libavcodec/arm/hevcdsp_init_neon.c +++ b/libavcodec/arm/hevcdsp_init_neon.c @@ -27,21 +27,39 @@ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); void ff_hevc_v_loop_filter_chroma_neon(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q); void ff_hevc_h_loop_filter_chroma_neon(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -void ff_hevc_transform_4x4_neon_8(int16_t *coeffs, int col_limit); -void ff_hevc_transform_8x8_neon_8(int16_t *coeffs, int col_limit); -void ff_hevc_idct_4x4_dc_neon_8(int16_t *coeffs); -void ff_hevc_idct_8x8_dc_neon_8(int16_t *coeffs); -void ff_hevc_idct_16x16_dc_neon_8(int16_t *coeffs); -void ff_hevc_idct_32x32_dc_neon_8(int16_t *coeffs); +void ff_hevc_add_residual_4x4_8_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_4x4_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_8x8_8_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_8x8_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_16x16_8_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_16x16_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_32x32_8_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_32x32_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_idct_4x4_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_8x8_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_16x16_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_32x32_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_4x4_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_8x8_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_16x16_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_32x32_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_4x4_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_4x4_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_10_neon(int16_t *coeffs, int col_limit); void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); -void ff_hevc_add_residual_4x4_neon_8(uint8_t *_dst, int16_t *coeffs, - ptrdiff_t stride); -void ff_hevc_add_residual_8x8_neon_8(uint8_t *_dst, int16_t *coeffs, - ptrdiff_t stride); -void ff_hevc_add_residual_16x16_neon_8(uint8_t *_dst, int16_t *coeffs, - ptrdiff_t stride); -void ff_hevc_add_residual_32x32_neon_8(uint8_t *_dst, int16_t *coeffs, - ptrdiff_t stride); #define PUT_PIXELS(name) \ void name(int16_t *dst, uint8_t *src, \ @@ -142,7 +160,7 @@ void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE); } -av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) +av_cold void ff_hevc_dsp_init_neon(HEVCDSPContext *c, const int bit_depth) { if (bit_depth == 8) { int x; @@ -150,16 +168,18 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_neon; c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_neon; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_neon; - c->idct[0] = ff_hevc_transform_4x4_neon_8; - c->idct[1] = ff_hevc_transform_8x8_neon_8; - c->idct_dc[0] = ff_hevc_idct_4x4_dc_neon_8; - c->idct_dc[1] = ff_hevc_idct_8x8_dc_neon_8; - c->idct_dc[2] = ff_hevc_idct_16x16_dc_neon_8; - c->idct_dc[3] = ff_hevc_idct_32x32_dc_neon_8; - c->add_residual[0] = ff_hevc_add_residual_4x4_neon_8; - c->add_residual[1] = ff_hevc_add_residual_8x8_neon_8; - c->add_residual[2] = ff_hevc_add_residual_16x16_neon_8; - c->add_residual[3] = ff_hevc_add_residual_32x32_neon_8; + c->add_residual[0] = ff_hevc_add_residual_4x4_8_neon; + c->add_residual[1] = ff_hevc_add_residual_8x8_8_neon; + c->add_residual[2] = ff_hevc_add_residual_16x16_8_neon; + c->add_residual[3] = ff_hevc_add_residual_32x32_8_neon; + c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_neon; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_8_neon; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_neon; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_neon; + c->idct[0] = ff_hevc_idct_4x4_8_neon; + c->idct[1] = ff_hevc_idct_8x8_8_neon; + c->idct[2] = ff_hevc_idct_16x16_8_neon; + c->idct[3] = ff_hevc_idct_32x32_8_neon; c->transform_4x4_luma = ff_hevc_transform_luma_4x4_neon_8; put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8; put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8; @@ -221,4 +241,21 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_qpel_uw_pixels_w48_neon_8; c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_qpel_uw_pixels_w64_neon_8; } + + if (bit_depth == 10) { + c->add_residual[0] = ff_hevc_add_residual_4x4_10_neon; + c->add_residual[1] = ff_hevc_add_residual_8x8_10_neon; + c->add_residual[2] = ff_hevc_add_residual_16x16_10_neon; + c->add_residual[3] = ff_hevc_add_residual_32x32_10_neon; + + c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_neon; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_neon; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_neon; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_neon; + + c->idct[0] = ff_hevc_idct_4x4_10_neon; + c->idct[1] = ff_hevc_idct_8x8_10_neon; + c->idct[2] = ff_hevc_idct_16x16_10_neon; + c->idct[3] = ff_hevc_idct_32x32_10_neon; + } } diff --git a/libavcodec/arm/sbrdsp_neon.S b/libavcodec/arm/sbrdsp_neon.S index e66abd682..003b04ea0 100644 --- a/libavcodec/arm/sbrdsp_neon.S +++ b/libavcodec/arm/sbrdsp_neon.S @@ -336,11 +336,11 @@ function ff_sbr_hf_apply_noise_0_neon, export=1 vld1.32 {d0}, [r0,:64] vld1.32 {d6}, [lr,:64] vld1.32 {d2[]}, [r1,:32]! - vld1.32 {d3[]}, [r2,:32]! + vld1.32 {d18[]}, [r2,:32]! vceq.f32 d4, d2, #0 veor d2, d2, d3 vmov d1, d0 - vmla.f32 d0, d6, d3 + vmla.f32 d0, d6, d18 vadd.f32 s2, s2, s4 vbif d0, d1, d4 vst1.32 {d0}, [r0,:64]! diff --git a/libavcodec/arm/vc1dsp_init_neon.c b/libavcodec/arm/vc1dsp_init_neon.c index 005d45ce8..2cca784f5 100644 --- a/libavcodec/arm/vc1dsp_init_neon.c +++ b/libavcodec/arm/vc1dsp_init_neon.c @@ -22,8 +22,6 @@ #include "libavcodec/vc1dsp.h" #include "vc1dsp.h" -#include "config.h" - void ff_vc1_inv_trans_8x8_neon(int16_t *block); void ff_vc1_inv_trans_4x8_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_8x4_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); @@ -95,7 +93,6 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPContext *dsp) dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_neon; dsp->put_vc1_mspel_pixels_tab[1][ 0] = ff_put_pixels8x8_neon; - if (HAVE_AS_DN_DIRECTIVE) { FN_ASSIGN(1, 0); FN_ASSIGN(2, 0); FN_ASSIGN(3, 0); @@ -114,7 +111,6 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPContext *dsp) FN_ASSIGN(1, 3); FN_ASSIGN(2, 3); FN_ASSIGN(3, 3); - } 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; diff --git a/libavcodec/arm/vc1dsp_neon.S b/libavcodec/arm/vc1dsp_neon.S index 611cbf223..de4d589bb 100644 --- a/libavcodec/arm/vc1dsp_neon.S +++ b/libavcodec/arm/vc1dsp_neon.S @@ -663,7 +663,6 @@ function ff_vc1_inv_trans_4x4_neon, export=1 bx lr endfunc -#if HAVE_AS_DN_DIRECTIVE @ The absolute value of multiplication constants from vc1_mspel_filter and vc1_mspel_{ver,hor}_filter_16bits. @ The sign is embedded in the code below that carries out the multiplication (mspel_filter{,.16}). #define MSPEL_MODE_1_MUL_CONSTANTS 4 53 18 3 @@ -689,22 +688,18 @@ endfunc @ Setup constants in registers for a subsequent use of mspel_filter{,.16}. .macro mspel_constants typesize reg_a reg_b reg_c reg_d filter_a filter_b filter_c filter_d reg_add filter_add_register - @ Define double-word register aliases. Typesize should be i8 or i16. - ra .dn \reg_a\().\typesize - rb .dn \reg_b\().\typesize - rc .dn \reg_c\().\typesize - rd .dn \reg_d\().\typesize + @ Typesize should be i8 or i16. @ Only set the register if the value is not 1 and unique .if \filter_a != 1 - vmov ra, #\filter_a @ ra = filter_a + vmov.\typesize \reg_a, #\filter_a @ reg_a = filter_a .endif - vmov rb, #\filter_b @ rb = filter_b + vmov.\typesize \reg_b, #\filter_b @ reg_b = filter_b .if \filter_b != \filter_c - vmov rc, #\filter_c @ rc = filter_c + vmov.\typesize \reg_c, #\filter_c @ reg_c = filter_c .endif .if \filter_d != 1 - vmov rd, #\filter_d @ rd = filter_d + vmov.\typesize \reg_d, #\filter_d @ reg_d = filter_d .endif @ vdup to double the size of typesize .ifc \typesize,i8 @@ -712,11 +707,6 @@ endfunc .else vdup.32 \reg_add, \filter_add_register @ reg_add = filter_add_register .endif - - .unreq ra - .unreq rb - .unreq rc - .unreq rd .endm @ After mspel_constants has been used, do the filtering. @@ -987,7 +977,6 @@ PUT_VC1_MSPEL_MC_V_ONLY(2) PUT_VC1_MSPEL_MC_V_ONLY(3) #undef PUT_VC1_MSPEL_MC_V_ONLY -#endif function ff_put_pixels8x8_neon, export=1 vld1.64 {d0}, [r1], r2 diff --git a/libavcodec/audioconvert.c b/libavcodec/audioconvert.c deleted file mode 100644 index 5e46fae2d..000000000 --- a/libavcodec/audioconvert.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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/common.h" -#include "libavutil/libm.h" -#include "libavutil/samplefmt.h" -#include "avcodec.h" -#include "audioconvert.h" - -#if FF_API_AUDIO_CONVERT - -struct AVAudioConvert { - int in_channels, out_channels; - int fmt_pair; -}; - -AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels, - enum AVSampleFormat in_fmt, int in_channels, - const float *matrix, int flags) -{ - AVAudioConvert *ctx; - if (in_channels!=out_channels) - return NULL; /* FIXME: not supported */ - ctx = av_malloc(sizeof(AVAudioConvert)); - if (!ctx) - return NULL; - ctx->in_channels = in_channels; - ctx->out_channels = out_channels; - ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt; - return ctx; -} - -void av_audio_convert_free(AVAudioConvert *ctx) -{ - av_free(ctx); -} - -int av_audio_convert(AVAudioConvert *ctx, - void * const out[6], const int out_stride[6], - const void * const in[6], const int in_stride[6], int len) -{ - int ch; - - //FIXME optimize common cases - - for(ch=0; chout_channels; ch++){ - const int is= in_stride[ch]; - const int os= out_stride[ch]; - const uint8_t *pi= in[ch]; - uint8_t *po= out[ch]; - uint8_t *end= po + os*len; - if(!out[ch]) - continue; - -#define CONV(ofmt, otype, ifmt, expr)\ -if(ctx->fmt_pair == ofmt + AV_SAMPLE_FMT_NB*ifmt){\ - do{\ - *(otype*)po = expr; pi += is; po += os;\ - }while(po < end);\ -} - -//FIXME put things below under ifdefs so we do not waste space for cases no codec will need -//FIXME rounding ? - - CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) - else return -1; - } - return 0; -} - -#endif /* FF_API_AUDIO_CONVERT */ diff --git a/libavcodec/audioconvert.h b/libavcodec/audioconvert.h deleted file mode 100644 index 996c3f37a..000000000 --- a/libavcodec/audioconvert.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 AVCODEC_AUDIOCONVERT_H -#define AVCODEC_AUDIOCONVERT_H - -#include "version.h" - -/** - * @file - * Audio format conversion routines - * This interface is deprecated and will be dropped in a future - * version. You should use the libswresample library instead. - */ - -#if FF_API_AUDIO_CONVERT - -#include "libavutil/cpu.h" -#include "avcodec.h" -#include "libavutil/channel_layout.h" - -struct AVAudioConvert; -typedef struct AVAudioConvert AVAudioConvert; - -/** - * Create an audio sample format converter context - * @param out_fmt Output sample format - * @param out_channels Number of output channels - * @param in_fmt Input sample format - * @param in_channels Number of input channels - * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore. - * @param flags See AV_CPU_FLAG_xx - * @return NULL on error - * @deprecated See libswresample - */ - -attribute_deprecated -AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels, - enum AVSampleFormat in_fmt, int in_channels, - const float *matrix, int flags); - -/** - * Free audio sample format converter context - * @deprecated See libswresample - */ - -attribute_deprecated -void av_audio_convert_free(AVAudioConvert *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] out_stride distance between consecutive output samples (measured in bytes) - * @param[in] in array of input buffers for each channel - * @param[in] in_stride distance between consecutive input samples (measured in bytes) - * @param len length of audio frame size (measured in samples) - * @deprecated See libswresample - */ - -attribute_deprecated -int av_audio_convert(AVAudioConvert *ctx, - void * const out[6], const int out_stride[6], - const void * const in[6], const int in_stride[6], int len); - -#endif /* FF_API_AUDIO_CONVERT */ - -#endif /* AVCODEC_AUDIOCONVERT_H */ diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c index 607d3ba4d..5c0a9de8f 100644 --- a/libavcodec/audiotoolboxdec.c +++ b/libavcodec/audiotoolboxdec.c @@ -24,7 +24,7 @@ #include "config.h" #include "avcodec.h" -#include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "bytestream.h" #include "internal.h" #include "mpegaudiodecheader.h" @@ -350,10 +350,10 @@ static av_cold int ffat_create_decoder(AVCodecContext *avctx, AVPacket *pkt) } else if (pkt && pkt->size >= 7 && (avctx->codec_id == AV_CODEC_ID_AC3 || avctx->codec_id == AV_CODEC_ID_EAC3)) { - AC3HeaderInfo hdr, *phdr = &hdr; + AC3HeaderInfo hdr; GetBitContext gbc; init_get_bits(&gbc, pkt->data, pkt->size); - if (avpriv_ac3_parse_header(&gbc, &phdr) < 0) + if (ff_ac3_parse_header(&gbc, &hdr) < 0) return AVERROR_INVALIDDATA; in_format.mSampleRate = hdr.sample_rate; in_format.mChannelsPerFrame = hdr.channels; @@ -597,6 +597,7 @@ static av_cold int ffat_close_decoder(AVCodecContext *avctx) .bsfs = bsf_name, \ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, \ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, \ + .wrapper_name = "at", \ }; FFAT_DEC(aac, AV_CODEC_ID_AAC, "aac_adtstoasc") diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index c47fbd1b2..2c1891693 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,8 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + + AVFrame* encoding_frame; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +444,10 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); + at->encoding_frame = av_frame_alloc(); + if (!at->encoding_frame) + return AVERROR(ENOMEM); + return 0; } @@ -453,6 +459,7 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac AVCodecContext *avctx = inctx; ATDecodeContext *at = avctx->priv_data; AVFrame *frame; + int ret; if (!at->frame_queue.available) { if (at->eof) { @@ -475,6 +482,13 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; + av_frame_unref(at->encoding_frame); + ret = av_frame_ref(at->encoding_frame, frame); + if (ret < 0) { + *nb_packets = 0; + return ret; + } + ff_bufqueue_add(avctx, &at->used_frame_queue, frame); return 0; @@ -565,6 +579,7 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); + av_frame_free(&at->encoding_frame); return 0; } @@ -619,6 +634,7 @@ static const AVOption options[] = { }, \ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, \ .profiles = PROFILES, \ + .wrapper_name = "at", \ }; static const uint64_t aac_at_channel_layouts[] = { diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 18c3e3ea1..8fbbc798a 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -36,6 +36,7 @@ #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" @@ -217,9 +218,6 @@ enum AVCodecID { /* video codecs */ AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding -#if FF_API_XVMC - AV_CODEC_ID_MPEG2VIDEO_XVMC, -#endif /* FF_API_XVMC */ AV_CODEC_ID_H261, AV_CODEC_ID_H263, AV_CODEC_ID_RV10, @@ -520,9 +518,6 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_G722, AV_CODEC_ID_ADPCM_IMA_APC, AV_CODEC_ID_ADPCM_VIMA, -#if FF_API_VIMA_DECODER - AV_CODEC_ID_VIMA = AV_CODEC_ID_ADPCM_VIMA, -#endif AV_CODEC_ID_ADPCM_AFC = 0x11800, AV_CODEC_ID_ADPCM_IMA_OKI, @@ -585,9 +580,6 @@ enum AVCodecID { AV_CODEC_ID_MLP, AV_CODEC_ID_GSM_MS, /* as found in WAV */ AV_CODEC_ID_ATRAC3, -#if FF_API_VOXWARE - AV_CODEC_ID_VOXWARE, -#endif AV_CODEC_ID_APE, AV_CODEC_ID_NELLYMOSER, AV_CODEC_ID_MUSEPACK8, @@ -641,6 +633,7 @@ enum AVCodecID { AV_CODEC_ID_ATRAC3AL, AV_CODEC_ID_ATRAC3PAL, AV_CODEC_ID_DOLBY_E, + AV_CODEC_ID_APTX, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -774,7 +767,7 @@ typedef struct AVCodecDescriptor { * 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 32 +#define AV_INPUT_BUFFER_PADDING_SIZE 64 /** * @ingroup lavc_encoding @@ -783,38 +776,6 @@ typedef struct AVCodecDescriptor { */ #define AV_INPUT_BUFFER_MIN_SIZE 16384 -#if FF_API_WITHOUT_PREFIX -/** - * @deprecated use AV_INPUT_BUFFER_PADDING_SIZE instead - */ -#define FF_INPUT_BUFFER_PADDING_SIZE 32 - -/** - * @deprecated use AV_INPUT_BUFFER_MIN_SIZE instead - */ -#define FF_MIN_BUFFER_SIZE 16384 -#endif /* FF_API_WITHOUT_PREFIX */ - -/** - * @ingroup lavc_encoding - * motion estimation type. - * @deprecated use codec private option instead - */ -#if FF_API_MOTION_EST -enum Motion_Est_ID { - ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed - ME_FULL, - ME_LOG, - ME_PHODS, - ME_EPZS, ///< enhanced predictive zonal search - ME_X1, ///< reserved for experiments - ME_HEX, ///< hexagon based search - ME_UMH, ///< uneven multi-hexagon search - ME_TESA, ///< transformed exhaustive search algorithm - ME_ITER=50, ///< iterative search -}; -#endif - /** * @ingroup lavc_decoding */ @@ -853,13 +814,6 @@ typedef struct RcOverride{ float quality_factor; } RcOverride; -#if FF_API_MAX_BFRAMES -/** - * @deprecated there is no libavcodec-wide limit on the number of B-frames - */ -#define FF_MAX_B_FRAMES 16 -#endif - /* encoding support These flags can be passed in AVCodecContext.flags before initialization. Note: Not everything is supported yet. @@ -1031,13 +985,6 @@ typedef struct RcOverride{ */ #define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) -#if FF_API_CAP_VDPAU -/** - * Codec can export data for HW decoding (VDPAU). - */ -#define AV_CODEC_CAP_HWACCEL_VDPAU (1 << 7) -#endif - /** * Codec can output multiple frames per AVPacket * Normally demuxers return one frame at a time, demuxers which do not do @@ -1098,231 +1045,26 @@ typedef struct RcOverride{ */ #define AV_CODEC_CAP_LOSSLESS 0x80000000 - -#if FF_API_WITHOUT_PREFIX /** - * Allow decoders to produce frames with data planes that are not aligned - * to CPU requirements (e.g. due to cropping). + * 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 CODEC_FLAG_UNALIGNED AV_CODEC_FLAG_UNALIGNED -#define CODEC_FLAG_QSCALE AV_CODEC_FLAG_QSCALE -#define CODEC_FLAG_4MV AV_CODEC_FLAG_4MV -#define CODEC_FLAG_OUTPUT_CORRUPT AV_CODEC_FLAG_OUTPUT_CORRUPT -#define CODEC_FLAG_QPEL AV_CODEC_FLAG_QPEL -#if FF_API_GMC -/** - * @deprecated use the "gmc" private option of the libxvid encoder - */ -#define CODEC_FLAG_GMC 0x0020 ///< Use GMC. -#endif -#if FF_API_MV0 -/** - * @deprecated use the flag "mv0" in the "mpv_flags" private option of the - * mpegvideo encoders - */ -#define CODEC_FLAG_MV0 0x0040 -#endif -#if FF_API_INPUT_PRESERVED -/** - * @deprecated passing reference-counted frames to the encoders replaces this - * flag - */ -#define CODEC_FLAG_INPUT_PRESERVED 0x0100 -#endif -#define CODEC_FLAG_PASS1 AV_CODEC_FLAG_PASS1 -#define CODEC_FLAG_PASS2 AV_CODEC_FLAG_PASS2 -#define CODEC_FLAG_GRAY AV_CODEC_FLAG_GRAY -#if FF_API_EMU_EDGE -/** - * @deprecated edges are not used/required anymore. I.e. this flag is now always - * set. - */ -#define CODEC_FLAG_EMU_EDGE 0x4000 -#endif -#define CODEC_FLAG_PSNR AV_CODEC_FLAG_PSNR -#define CODEC_FLAG_TRUNCATED AV_CODEC_FLAG_TRUNCATED - -#if FF_API_NORMALIZE_AQP -/** - * @deprecated use the flag "naq" in the "mpv_flags" private option of the - * mpegvideo encoders - */ -#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 -#endif -#define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT -#define CODEC_FLAG_LOW_DELAY AV_CODEC_FLAG_LOW_DELAY -#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER -#define CODEC_FLAG_BITEXACT AV_CODEC_FLAG_BITEXACT -#define CODEC_FLAG_AC_PRED AV_CODEC_FLAG_AC_PRED -#define CODEC_FLAG_LOOP_FILTER AV_CODEC_FLAG_LOOP_FILTER -#define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME -#define CODEC_FLAG_CLOSED_GOP AV_CODEC_FLAG_CLOSED_GOP -#define CODEC_FLAG2_FAST AV_CODEC_FLAG2_FAST -#define CODEC_FLAG2_NO_OUTPUT AV_CODEC_FLAG2_NO_OUTPUT -#define CODEC_FLAG2_LOCAL_HEADER AV_CODEC_FLAG2_LOCAL_HEADER -#define CODEC_FLAG2_DROP_FRAME_TIMECODE AV_CODEC_FLAG2_DROP_FRAME_TIMECODE -#define CODEC_FLAG2_IGNORE_CROP AV_CODEC_FLAG2_IGNORE_CROP - -#define CODEC_FLAG2_CHUNKS AV_CODEC_FLAG2_CHUNKS -#define CODEC_FLAG2_SHOW_ALL AV_CODEC_FLAG2_SHOW_ALL -#define CODEC_FLAG2_EXPORT_MVS AV_CODEC_FLAG2_EXPORT_MVS -#define CODEC_FLAG2_SKIP_MANUAL AV_CODEC_FLAG2_SKIP_MANUAL - -/* Unsupported options : - * Syntax Arithmetic coding (SAC) - * Reference Picture Selection - * Independent Segment Decoding */ -/* /Fx */ -/* codec capabilities */ - -#define CODEC_CAP_DRAW_HORIZ_BAND AV_CODEC_CAP_DRAW_HORIZ_BAND ///< Decoder can use draw_horiz_band callback. -/** - * 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 CODEC_CAP_DR1 AV_CODEC_CAP_DR1 -#define CODEC_CAP_TRUNCATED AV_CODEC_CAP_TRUNCATED -#if FF_API_XVMC -/* Codec can export data for HW decoding. This flag indicates that - * the codec would call get_format() with list that might contain HW accelerated - * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them - * including raw image format. - * The application can use the passed context to determine bitstream version, - * chroma format, resolution etc. - */ -#define CODEC_CAP_HWACCEL 0x0010 -#endif /* FF_API_XVMC */ -/** - * 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 CODEC_CAP_DELAY AV_CODEC_CAP_DELAY -/** - * Codec can be fed a final frame with a smaller size. - * This can be used to prevent truncation of the last audio samples. - */ -#define CODEC_CAP_SMALL_LAST_FRAME AV_CODEC_CAP_SMALL_LAST_FRAME -#if FF_API_CAP_VDPAU -/** - * Codec can export data for HW decoding (VDPAU). - */ -#define CODEC_CAP_HWACCEL_VDPAU AV_CODEC_CAP_HWACCEL_VDPAU -#endif -/** - * 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 CODEC_CAP_SUBFRAMES AV_CODEC_CAP_SUBFRAMES -/** - * Codec is experimental and is thus avoided in favor of non experimental - * encoders - */ -#define CODEC_CAP_EXPERIMENTAL AV_CODEC_CAP_EXPERIMENTAL -/** - * Codec should fill in channel configuration and samplerate instead of container - */ -#define CODEC_CAP_CHANNEL_CONF AV_CODEC_CAP_CHANNEL_CONF -#if FF_API_NEG_LINESIZES -/** - * @deprecated no codecs use this capability - */ -#define CODEC_CAP_NEG_LINESIZES 0x0800 -#endif -/** - * Codec supports frame-level multithreading. - */ -#define CODEC_CAP_FRAME_THREADS AV_CODEC_CAP_FRAME_THREADS -/** - * Codec supports slice-based (or partition-based) multithreading. - */ -#define CODEC_CAP_SLICE_THREADS AV_CODEC_CAP_SLICE_THREADS -/** - * Codec supports changed parameters at any point. - */ -#define CODEC_CAP_PARAM_CHANGE AV_CODEC_CAP_PARAM_CHANGE -/** - * Codec supports avctx->thread_count == 0 (auto). - */ -#define CODEC_CAP_AUTO_THREADS AV_CODEC_CAP_AUTO_THREADS -/** - * Audio encoder supports receiving a different number of samples in each call. - */ -#define CODEC_CAP_VARIABLE_FRAME_SIZE AV_CODEC_CAP_VARIABLE_FRAME_SIZE -/** - * Codec is intra only. - */ -#define CODEC_CAP_INTRA_ONLY AV_CODEC_CAP_INTRA_ONLY -/** - * Codec is lossless. - */ -#define CODEC_CAP_LOSSLESS AV_CODEC_CAP_LOSSLESS +#define AV_CODEC_CAP_HARDWARE (1 << 18) /** - * HWAccel is experimental and is thus avoided in favor of non experimental - * codecs + * 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 HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200 -#endif /* FF_API_WITHOUT_PREFIX */ - -#if FF_API_MB_TYPE -//The following defines may change, don't expect compatibility if you use them. -#define MB_TYPE_INTRA4x4 0x0001 -#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific -#define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific -#define MB_TYPE_16x16 0x0008 -#define MB_TYPE_16x8 0x0010 -#define MB_TYPE_8x16 0x0020 -#define MB_TYPE_8x8 0x0040 -#define MB_TYPE_INTERLACED 0x0080 -#define MB_TYPE_DIRECT2 0x0100 //FIXME -#define MB_TYPE_ACPRED 0x0200 -#define MB_TYPE_GMC 0x0400 -#define MB_TYPE_SKIP 0x0800 -#define MB_TYPE_P0L0 0x1000 -#define MB_TYPE_P1L0 0x2000 -#define MB_TYPE_P0L1 0x4000 -#define MB_TYPE_P1L1 0x8000 -#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 0x00010000 -#define MB_TYPE_CBP 0x00020000 -// Note bits 24-31 are reserved for codec specific use (H.264 ref0, MPEG-1 0mv, ...) -#endif +#define AV_CODEC_CAP_HYBRID (1 << 19) /** * Pan Scan area. * This specifies the area which should be displayed. * Note there may be multiple such areas for one frame. */ -typedef struct AVPanScan{ +typedef struct AVPanScan { /** * id * - encoding: Set by user. @@ -1344,7 +1086,7 @@ typedef struct AVPanScan{ * - decoding: Set by libavcodec. */ int16_t position[3][2]; -}AVPanScan; +} AVPanScan; /** * This structure describes the bitrate properties of an encoded bitstream. It @@ -1384,13 +1126,6 @@ typedef struct AVCPBProperties { uint64_t vbv_delay; } AVCPBProperties; -#if FF_API_QSCALE_TYPE -#define FF_QSCALE_TYPE_MPEG1 0 -#define FF_QSCALE_TYPE_MPEG2 1 -#define FF_QSCALE_TYPE_H264 2 -#define FF_QSCALE_TYPE_VP56 3 -#endif - /** * The decoder will keep a reference to the frame and may reuse it later. */ @@ -1518,7 +1253,7 @@ enum AVPacketSideDataType { * u8 reason for end skip (0=padding silence, 1=convergence) * @endcode */ - AV_PKT_DATA_SKIP_SAMPLES=70, + AV_PKT_DATA_SKIP_SAMPLES, /** * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that @@ -1607,7 +1342,7 @@ enum AVPacketSideDataType { AV_PKT_DATA_A53_CC, /** - * The number of side data elements (in fact a bit more than it). + * 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. @@ -1723,6 +1458,12 @@ typedef struct AVPacket { * 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, @@ -1768,13 +1509,6 @@ typedef struct AVCodecContext { enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ const struct AVCodec *codec; -#if FF_API_CODEC_NAME - /** - * @deprecated this field is not used for anything in libavcodec - */ - attribute_deprecated - char codec_name[32]; -#endif enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ /** @@ -1792,14 +1526,6 @@ typedef struct AVCodecContext { */ unsigned int codec_tag; -#if FF_API_STREAM_CODEC_TAG - /** - * @deprecated this field is unused - */ - attribute_deprecated - unsigned int stream_codec_tag; -#endif - void *priv_data; /** @@ -1962,10 +1688,6 @@ typedef struct AVCodecContext { */ int coded_width, coded_height; -#if FF_API_ASPECT_EXTENDED -#define FF_ASPECT_EXTENDED 15 -#endif - /** * the number of pictures in a group of pictures, or 0 for intra_only * - encoding: Set by user. @@ -1988,14 +1710,6 @@ typedef struct AVCodecContext { */ enum AVPixelFormat pix_fmt; -#if FF_API_MOTION_EST - /** - * This option does nothing - * @deprecated use codec private options instead - */ - attribute_deprecated int me_method; -#endif - /** * If non NULL, 'draw_horiz_band' is called by the libavcodec * decoder to draw a horizontal band. It improves cache usage. Not @@ -2055,12 +1769,6 @@ typedef struct AVCodecContext { */ float b_quant_factor; -#if FF_API_RC_STRATEGY - /** @deprecated use codec private option instead */ - attribute_deprecated int rc_strategy; -#define FF_RC_STRATEGY_XVID 1 -#endif - #if FF_API_PRIVATE_OPT /** @deprecated use encoder private options instead */ attribute_deprecated @@ -2254,26 +1962,6 @@ typedef struct AVCodecContext { */ int me_subpel_quality; -#if FF_API_AFD - /** - * DTG active format information (additional aspect ratio - * information only used in DVB MPEG-2 transport streams) - * 0 if not set. - * - * - encoding: unused - * - decoding: Set by decoder. - * @deprecated Deprecated in favor of AVSideData - */ - attribute_deprecated int dtg_active_format; -#define FF_DTG_AFD_SAME 8 -#define FF_DTG_AFD_4_3 9 -#define FF_DTG_AFD_16_9 10 -#define FF_DTG_AFD_14_9 11 -#define FF_DTG_AFD_4_3_SP_14_9 13 -#define FF_DTG_AFD_16_9_SP_14_9 14 -#define FF_DTG_AFD_SP_4_3 15 -#endif /* FF_API_AFD */ - /** * maximum motion estimation search range in subpel units * If 0 then no limit. @@ -2283,19 +1971,6 @@ typedef struct AVCodecContext { */ int me_range; -#if FF_API_QUANT_BIAS - /** - * @deprecated use encoder private option instead - */ - attribute_deprecated int intra_quant_bias; -#define FF_DEFAULT_QUANT_BIAS 999999 - - /** - * @deprecated use encoder private option instead - */ - attribute_deprecated int inter_quant_bias; -#endif - /** * slice flags * - encoding: unused @@ -2306,16 +1981,6 @@ typedef struct AVCodecContext { #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) -#if FF_API_XVMC - /** - * XVideo Motion Acceleration - * - encoding: forbidden - * - decoding: set by decoder - * @deprecated XvMC doesn't need it anymore. - */ - attribute_deprecated int xvmc_acceleration; -#endif /* FF_API_XVMC */ - /** * macroblock decision mode * - encoding: Set by user. @@ -2350,20 +2015,6 @@ typedef struct AVCodecContext { int noise_reduction; #endif -#if FF_API_MPV_OPT - /** - * @deprecated this field is unused - */ - attribute_deprecated - int me_threshold; - - /** - * @deprecated this field is unused - */ - attribute_deprecated - int mb_threshold; -#endif - /** * precision of the intra DC coefficient - 8 * - encoding: Set by user. @@ -2385,14 +2036,6 @@ typedef struct AVCodecContext { */ int skip_bottom; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - float border_masking; -#endif - /** * minimum MB Lagrange multiplier * - encoding: Set by user. @@ -2447,15 +2090,6 @@ typedef struct AVCodecContext { int chromaoffset; #endif -#if FF_API_UNUSED_MEMBERS - /** - * Multiplied by qscale for each frame and added to scene_change_score. - * - encoding: Set by user. - * - decoding: unused - */ - attribute_deprecated int scenechange_factor; -#endif - /** * Note: Value depends upon the compare function used for fullpel ME. * - encoding: Set by user. @@ -2718,19 +2352,6 @@ typedef struct AVCodecContext { */ int max_qdiff; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - float rc_qsquish; - - attribute_deprecated - float rc_qmod_amp; - attribute_deprecated - int rc_qmod_freq; -#endif - /** * decoder bitstream buffer size * - encoding: Set by user. @@ -2746,14 +2367,6 @@ typedef struct AVCodecContext { int rc_override_count; RcOverride *rc_override; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - const char *rc_eq; -#endif - /** * maximum bitrate * - encoding: Set by user. @@ -2768,17 +2381,6 @@ typedef struct AVCodecContext { */ int64_t rc_min_rate; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - float rc_buffer_aggressivity; - - attribute_deprecated - float rc_initial_cplx; -#endif - /** * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. * - encoding: Set by user. @@ -2805,9 +2407,6 @@ typedef struct AVCodecContext { #define FF_CODER_TYPE_AC 1 #define FF_CODER_TYPE_RAW 2 #define FF_CODER_TYPE_RLE 3 -#if FF_API_UNUSED_MEMBERS -#define FF_CODER_TYPE_DEFLATE 4 -#endif /* FF_API_UNUSED_MEMBERS */ /** * @deprecated use encoder private options instead */ @@ -2821,20 +2420,6 @@ typedef struct AVCodecContext { int context_model; #endif -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - int lmin; - - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - int lmax; -#endif - #if FF_API_PRIVATE_OPT /** @deprecated use encoder private options instead */ attribute_deprecated @@ -2945,16 +2530,10 @@ typedef struct AVCodecContext { */ int workaround_bugs; #define FF_BUG_AUTODETECT 1 ///< autodetection -#if FF_API_OLD_MSMPEG4 -#define FF_BUG_OLD_MSMPEG4 2 -#endif #define FF_BUG_XVID_ILACE 4 #define FF_BUG_UMP4 8 #define FF_BUG_NO_PADDING 16 #define FF_BUG_AMV 32 -#if FF_API_AC_VLC -#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. -#endif #define FF_BUG_QPEL_CHROMA 64 #define FF_BUG_STD_QPEL 128 #define FF_BUG_QPEL_CHROMA2 256 @@ -3015,9 +2594,6 @@ typedef struct AVCodecContext { #define FF_DEBUG_DCT_COEFF 0x00000040 #define FF_DEBUG_SKIP 0x00000080 #define FF_DEBUG_STARTCODE 0x00000100 -#if FF_API_UNUSED_MEMBERS -#define FF_DEBUG_PTS 0x00000200 -#endif /* FF_API_UNUSED_MEMBERS */ #define FF_DEBUG_ER 0x00000400 #define FF_DEBUG_MMCO 0x00000800 #define FF_DEBUG_BUGS 0x00001000 @@ -3079,7 +2655,7 @@ typedef struct AVCodecContext { * - encoding: unused. * - decoding: Set by libavcodec */ - struct AVHWAccel *hwaccel; + const struct AVHWAccel *hwaccel; /** * Hardware accelerator context. @@ -3125,27 +2701,12 @@ typedef struct AVCodecContext { #define FF_IDCT_SIMPLEMMX 3 #define FF_IDCT_ARM 7 #define FF_IDCT_ALTIVEC 8 -#if FF_API_ARCH_SH4 -#define FF_IDCT_SH4 9 -#endif #define FF_IDCT_SIMPLEARM 10 -#if FF_API_UNUSED_MEMBERS -#define FF_IDCT_IPP 13 -#endif /* FF_API_UNUSED_MEMBERS */ #define FF_IDCT_XVID 14 -#if FF_API_IDCT_XVIDMMX -#define FF_IDCT_XVIDMMX 14 -#endif /* FF_API_IDCT_XVIDMMX */ #define FF_IDCT_SIMPLEARMV5TE 16 #define FF_IDCT_SIMPLEARMV6 17 -#if FF_API_ARCH_SPARC -#define FF_IDCT_SIMPLEVIS 18 -#endif #define FF_IDCT_FAAN 20 #define FF_IDCT_SIMPLENEON 22 -#if FF_API_ARCH_ALPHA -#define FF_IDCT_SIMPLEALPHA 23 -#endif #define FF_IDCT_NONE 24 /* Used by XvMC to extract IDCT coefficients with FF_IDCT_PERM_NONE */ #define FF_IDCT_SIMPLEAUTO 128 @@ -3396,15 +2957,6 @@ typedef struct AVCodecContext { uint8_t *subtitle_header; int subtitle_header_size; -#if FF_API_ERROR_RATE - /** - * @deprecated use the 'error_rate' private AVOption of the mpegvideo - * encoders - */ - attribute_deprecated - int error_rate; -#endif - #if FF_API_VBV_DELAY /** * VBV delay coded in the last frame (in periods of a 27 MHz clock). @@ -3704,22 +3256,41 @@ typedef struct AVCodecContext { int apply_cropping; } 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. @@ -3729,6 +3300,61 @@ typedef struct AVProfile { 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; @@ -3765,6 +3391,18 @@ typedef struct AVCodec { 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 @@ -3854,14 +3492,39 @@ typedef struct AVCodec { * 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 { @@ -3906,7 +3569,6 @@ typedef struct AVHWAccel { * New public fields should be added right above. ***************************************************************** */ - struct AVHWAccel *next; /** * Allocate a custom buffer @@ -3929,6 +3591,20 @@ typedef struct AVHWAccel { */ 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. * @@ -4001,6 +3677,16 @@ typedef struct AVHWAccel { * 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; /** @@ -4831,21 +4517,6 @@ AVCodec *avcodec_find_decoder_by_name(const char *name); */ int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); -#if FF_API_EMU_EDGE -/** - * Return the amount of padding in pixels which the get_buffer callback must - * provide around the edge of the image for codecs which do not have the - * CODEC_FLAG_EMU_EDGE flag. - * - * @return Required padding in pixels. - * - * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer - * needed - */ -attribute_deprecated -unsigned avcodec_get_edge_width(void); -#endif - /** * 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 @@ -5151,6 +4822,109 @@ int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); */ 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 @@ -5516,103 +5290,6 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, * @} */ -#if FF_API_AVCODEC_RESAMPLE -/** - * @defgroup lavc_resample Audio resampling - * @ingroup libavc - * @deprecated use libswresample instead - * - * @{ - */ -struct ReSampleContext; -struct AVResampleContext; - -typedef struct ReSampleContext ReSampleContext; - -/** - * Initialize audio resampling context. - * - * @param output_channels number of output channels - * @param input_channels number of input channels - * @param output_rate output sample rate - * @param input_rate input sample rate - * @param sample_fmt_out requested output sample format - * @param sample_fmt_in input sample format - * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency - * @param log2_phase_count log2 of the number of entries in the polyphase filterbank - * @param linear if 1 then the used FIR filter will be linearly interpolated - between the 2 closest, if 0 the closest will be used - * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate - * @return allocated ReSampleContext, NULL if error occurred - */ -attribute_deprecated -ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate, - enum AVSampleFormat sample_fmt_out, - enum AVSampleFormat sample_fmt_in, - int filter_length, int log2_phase_count, - int linear, double cutoff); - -attribute_deprecated -int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); - -/** - * Free resample context. - * - * @param s a non-NULL pointer to a resample context previously - * created with av_audio_resample_init() - */ -attribute_deprecated -void audio_resample_close(ReSampleContext *s); - - -/** - * Initialize an audio resampler. - * Note, if either rate is not an integer then simply scale both rates up so they are. - * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq - * @param log2_phase_count log2 of the number of entries in the polyphase filterbank - * @param linear If 1 then the used FIR filter will be linearly interpolated - between the 2 closest, if 0 the closest will be used - * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate - */ -attribute_deprecated -struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); - -/** - * Resample an array of samples using a previously configured context. - * @param src an array of unconsumed samples - * @param consumed the number of samples of src which have been consumed are returned here - * @param src_size the number of unconsumed samples available - * @param dst_size the amount of space in samples available in dst - * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. - * @return the number of samples written in dst or -1 if an error occurred - */ -attribute_deprecated -int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); - - -/** - * Compensate samplerate/timestamp drift. The compensation is done by changing - * the resampler parameters, so no audible clicks or similar distortions occur - * @param compensation_distance distance in output samples over which the compensation should be performed - * @param sample_delta number of output samples which should be output less - * - * example: av_resample_compensate(c, 10, 500) - * here instead of 510 samples only 500 samples would be output - * - * note, due to rounding the actual compensation might be slightly different, - * especially if the compensation_distance is large and the in_rate used during init is small - */ -attribute_deprecated -void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); -attribute_deprecated -void av_resample_close(struct AVResampleContext *c); - -/** - * @} - */ -#endif - #if FF_API_AVPICTURE /** * @addtogroup lavc_picture @@ -5753,14 +5430,6 @@ enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const en * @} */ -#if FF_API_SET_DIMENSIONS -/** - * @deprecated this function is not supposed to be used from outside of lavc - */ -attribute_deprecated -void avcodec_set_dimensions(AVCodecContext *s, int width, int height); -#endif - #if FF_API_TAG_STRING /** * Put a string representing the codec tag codec_tag in buf. @@ -5997,84 +5666,42 @@ typedef struct AVBitStreamFilter { #if FF_API_OLD_BSF /** - * Register a bitstream filter. - * - * The filter will be accessible to the application code through - * av_bitstream_filter_next() or can be directly initialized with - * av_bitstream_filter_init(). - * - * @see avcodec_register_all() + * @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); - /** - * Create and initialize a bitstream filter context given a bitstream - * filter name. - * - * The returned context must be freed with av_bitstream_filter_close(). - * - * @param name the name of the bitstream filter - * @return a bitstream filter context if a matching filter was found - * and successfully initialized, NULL otherwise + * @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); - /** - * Filter bitstream. - * - * This function filters the buffer buf with size buf_size, and places the - * filtered buffer in the buffer pointed to by poutbuf. - * - * The output buffer must be freed by the caller. - * - * @param bsfc bitstream filter context created by av_bitstream_filter_init() - * @param avctx AVCodecContext accessed by the filter, may be NULL. - * If specified, this must point to the encoder context of the - * output stream the packet is sent to. - * @param args arguments which specify the filter configuration, may be NULL - * @param poutbuf pointer which is updated to point to the filtered buffer - * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes - * @param buf buffer containing the data to filter - * @param buf_size size in bytes of buf - * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data - * @return >= 0 in case of success, or a negative error code in case of failure - * - * If the return value is positive, an output buffer is allocated and - * is available in *poutbuf, and is distinct from the input buffer. - * - * If the return value is 0, the output buffer is not allocated and - * should be considered identical to the input buffer, or in case - * *poutbuf was set it points to the input buffer (not necessarily to - * its starting address). A special case is if *poutbuf was set to NULL and - * *poutbuf_size was set to 0, which indicates the packet should be dropped. + * @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); - /** - * Release bitstream filter context. - * - * @param bsf the bitstream filter context created with - * av_bitstream_filter_init(), can be NULL + * @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); - /** - * If f is NULL, return the first registered bitstream filter, - * if f is non-NULL, return the next registered bitstream filter - * after f, or NULL if f is the last one. - * - * This function can be used to iterate over all registered bitstream - * filters. + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_next() from the new bitstream filtering API (using + * AVBSFContext). */ attribute_deprecated -AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); +const AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); #endif /** @@ -6282,51 +5909,32 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); */ unsigned int av_xiphlacing(unsigned char *s, unsigned int v); -#if FF_API_MISSING_SAMPLE -/** - * Log a generic warning message about a missing feature. This function is - * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) - * only, and would normally not be used by applications. - * @param[in] avc a pointer to an arbitrary struct of which the first field is - * a pointer to an AVClass struct - * @param[in] feature string containing the name of the missing feature - * @param[in] want_sample indicates if samples are wanted which exhibit this feature. - * If want_sample is non-zero, additional verbiage will be added to the log - * message which tells the user how to report samples to the development - * mailing list. - * @deprecated Use avpriv_report_missing_feature() instead. - */ -attribute_deprecated -void av_log_missing_feature(void *avc, const char *feature, int want_sample); - -/** - * Log a generic warning message asking for a sample. This function is - * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) - * only, and would normally not be used by applications. - * @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 an optional message, or NULL if no message - * @deprecated Use avpriv_request_sample() instead. - */ -attribute_deprecated -void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); -#endif /* FF_API_MISSING_SAMPLE */ - +#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 @@ -6357,8 +5965,13 @@ enum AVLockOp { * 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. diff --git a/libavcodec/avdct.c b/libavcodec/avdct.c index 80aca8872..860f86595 100644 --- a/libavcodec/avdct.c +++ b/libavcodec/avdct.c @@ -48,19 +48,10 @@ static const AVOption avdct_options[] = { {"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"}, -#if FF_API_ARCH_SH4 -{"sh4", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SH4 }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif {"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"}, -#if FF_API_ARCH_ALPHA -{"simplealpha", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEALPHA }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif -#if FF_API_UNUSED_MEMBERS -{"ipp", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_IPP }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif {"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"}, diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c index d1f4ea9eb..90b821592 100644 --- a/libavcodec/avpacket.c +++ b/libavcodec/avpacket.c @@ -479,34 +479,6 @@ int av_packet_split_side_data(AVPacket *pkt){ } #endif -#if FF_API_MERGE_SD -int ff_packet_split_and_drop_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 0; - } - pkt->size = p - pkt->data - size; - av_assert0(pkt->size >= 0); - return 1; - } - return 0; -} -#endif - uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size) { AVDictionaryEntry *t = NULL; diff --git a/libavcodec/avrndec.c b/libavcodec/avrndec.c index c37f99661..104ff2d90 100644 --- a/libavcodec/avrndec.c +++ b/libavcodec/avrndec.c @@ -168,7 +168,6 @@ AVCodec ff_avrn_decoder = { .init = init, .close = end, .decode = decode_frame, - .capabilities = AV_CODEC_CAP_DR1, .max_lowres = 3, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; diff --git a/libavcodec/bink.c b/libavcodec/bink.c index 346b6cda9..c4cf617a8 100644 --- a/libavcodec/bink.c +++ b/libavcodec/bink.c @@ -601,17 +601,16 @@ static inline int binkb_get_value(BinkContext *c, int bundle_num) * @param quant_matrices quantization matrices * @return 0 for success, negative value in other cases */ -static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], const uint8_t *scan, - const int32_t quant_matrices[16][64], int q) +static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], + const uint8_t *scan, int *coef_count_, + int coef_idx[64], int q) { int coef_list[128]; int mode_list[128]; int i, t, bits, ccoef, mode, sign; int list_start = 64, list_end = 64, list_pos; int coef_count = 0; - int coef_idx[64]; int quant_idx; - const int32_t *quant; coef_list[list_end] = 4; mode_list[list_end++] = 0; coef_list[list_end] = 24; mode_list[list_end++] = 0; @@ -690,15 +689,21 @@ static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], const uint8_t * } } - quant = quant_matrices[quant_idx]; + *coef_count_ = coef_count; + return quant_idx; +} + +static void unquantize_dct_coeffs(int32_t block[64], const int32_t quant[64], + int coef_count, int coef_idx[64], + const uint8_t *scan) +{ + int i; block[0] = (block[0] * quant[0]) >> 11; for (i = 0; i < coef_count; i++) { int idx = coef_idx[i]; block[scan[idx]] = (block[scan[idx]] * quant[idx]) >> 11; } - - return 0; } /** @@ -817,7 +822,7 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, LOCAL_ALIGNED_16(int32_t, dctblock, [64]); int coordmap[64]; int ybias = is_key ? -15 : 0; - int qp; + int qp, quant_idx, coef_count, coef_idx[64]; const int stride = frame->linesize[plane_idx]; int bw = is_chroma ? (c->avctx->width + 15) >> 4 : (c->avctx->width + 7) >> 3; @@ -872,7 +877,9 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = binkb_get_value(c, BINKB_SRC_INTRA_DC); qp = binkb_get_value(c, BINKB_SRC_INTRA_Q); - read_dct_coeffs(gb, dctblock, bink_scan, (const int32_t (*)[64])binkb_intra_quant, qp); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, binkb_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(dst, stride, dctblock); break; case 3: @@ -905,7 +912,9 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = binkb_get_value(c, BINKB_SRC_INTER_DC); qp = binkb_get_value(c, BINKB_SRC_INTER_Q); - read_dct_coeffs(gb, dctblock, bink_scan, (const int32_t (*)[64])binkb_inter_quant, qp); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, binkb_inter_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_add(dst, stride, dctblock); break; case 5: @@ -979,7 +988,7 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, LOCAL_ALIGNED_32(int16_t, block, [64]); LOCAL_ALIGNED_16(uint8_t, ublock, [64]); LOCAL_ALIGNED_16(int32_t, dctblock, [64]); - int coordmap[64]; + int coordmap[64], quant_idx, coef_count, coef_idx[64]; const int stride = frame->linesize[plane_idx]; int bw = is_chroma ? (c->avctx->width + 15) >> 4 : (c->avctx->width + 7) >> 3; @@ -1065,7 +1074,9 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, case INTRA_BLOCK: memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTRA_DC); - read_dct_coeffs(gb, dctblock, bink_scan, bink_intra_quant, -1); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, bink_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(ublock, 8, dctblock); break; case FILL_BLOCK: @@ -1138,7 +1149,9 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, case INTRA_BLOCK: memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTRA_DC); - read_dct_coeffs(gb, dctblock, bink_scan, bink_intra_quant, -1); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, bink_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(dst, stride, dctblock); break; case FILL_BLOCK: @@ -1152,7 +1165,9 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, return ret; memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTER_DC); - read_dct_coeffs(gb, dctblock, bink_scan, bink_inter_quant, -1); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, bink_inter_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_add(dst, stride, dctblock); break; case PATTERN_BLOCK: diff --git a/libavcodec/bitstream_filter.c b/libavcodec/bitstream_filter.c index 8599b90d4..ed1cf3335 100644 --- a/libavcodec/bitstream_filter.c +++ b/libavcodec/bitstream_filter.c @@ -28,7 +28,7 @@ #if FF_API_OLD_BSF FF_DISABLE_DEPRECATION_WARNINGS -AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) +const AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) { const AVBitStreamFilter *filter = NULL; void *opaque = NULL; @@ -131,7 +131,7 @@ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, return ret; } - pkt.data = buf; + pkt.data = (uint8_t *)buf; pkt.size = buf_size; ret = av_bsf_send_packet(priv->ctx, &pkt); diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index ce34de640..7b0cb5032 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -29,18 +29,23 @@ extern const AVBitStreamFilter ff_chomp_bsf; extern const AVBitStreamFilter ff_dump_extradata_bsf; extern const AVBitStreamFilter ff_dca_core_bsf; extern const AVBitStreamFilter ff_extract_extradata_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_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_remove_extradata_bsf; extern const AVBitStreamFilter ff_text2movsub_bsf; +extern const AVBitStreamFilter ff_trace_headers_bsf; extern const AVBitStreamFilter ff_vp9_raw_reorder_bsf; extern const AVBitStreamFilter ff_vp9_superframe_bsf; extern const AVBitStreamFilter ff_vp9_superframe_split_bsf; diff --git a/libavcodec/blockdsp.h b/libavcodec/blockdsp.h index 6e27a02ba..26fc2ea13 100644 --- a/libavcodec/blockdsp.h +++ b/libavcodec/blockdsp.h @@ -33,8 +33,8 @@ 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 16 */); - void (*clear_blocks)(int16_t *blocks /* align 16 */); + void (*clear_block)(int16_t *block /* align 32 */); + void (*clear_blocks)(int16_t *blocks /* align 32 */); op_fill_func fill_block_tab[2]; } BlockDSPContext; diff --git a/libavcodec/cabac.c b/libavcodec/cabac.c index dd2b057c6..e51139de3 100644 --- a/libavcodec/cabac.c +++ b/libavcodec/cabac.c @@ -32,7 +32,7 @@ #include "cabac.h" #include "cabac_functions.h" -const uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63] = { +DECLARE_ASM_ALIGNED(1, const uint8_t, ff_h264_cabac_tables)[512 + 4*2*64 + 4*64 + 63] = { 9,8,7,7,6,6,6,6,5,5,5,5,5,5,5,5, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c new file mode 100644 index 000000000..97ab520c2 --- /dev/null +++ b/libavcodec/cbs.c @@ -0,0 +1,491 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/avassert.h" +#include "libavutil/common.h" + +#include "cbs.h" +#include "cbs_internal.h" + + +static const CodedBitstreamType *cbs_type_table[] = { +#if CONFIG_CBS_H264 + &ff_cbs_type_h264, +#endif +#if CONFIG_CBS_H265 + &ff_cbs_type_h265, +#endif +#if CONFIG_CBS_MPEG2 + &ff_cbs_type_mpeg2, +#endif +}; + +int ff_cbs_init(CodedBitstreamContext **ctx_ptr, + enum AVCodecID codec_id, void *log_ctx) +{ + CodedBitstreamContext *ctx; + const CodedBitstreamType *type; + int i; + + type = NULL; + for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { + if (cbs_type_table[i]->codec_id == codec_id) { + type = cbs_type_table[i]; + break; + } + } + if (!type) + return AVERROR(EINVAL); + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + ctx->log_ctx = log_ctx; + ctx->codec = type; + + ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); + if (!ctx->priv_data) { + av_freep(&ctx); + return AVERROR(ENOMEM); + } + + ctx->decompose_unit_types = NULL; + + ctx->trace_enable = 0; + ctx->trace_level = AV_LOG_TRACE; + + *ctx_ptr = ctx; + return 0; +} + +void ff_cbs_close(CodedBitstreamContext **ctx_ptr) +{ + CodedBitstreamContext *ctx = *ctx_ptr; + + if (!ctx) + return; + + if (ctx->codec && ctx->codec->close) + ctx->codec->close(ctx); + + av_freep(&ctx->priv_data); + av_freep(ctx_ptr); +} + +static void cbs_unit_uninit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + if (ctx->codec->free_unit && unit->content && !unit->content_external) + ctx->codec->free_unit(unit); + + av_freep(&unit->data); + unit->data_size = 0; + unit->data_bit_padding = 0; +} + +void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int i; + + for (i = 0; i < frag->nb_units; i++) + cbs_unit_uninit(ctx, &frag->units[i]); + av_freep(&frag->units); + frag->nb_units = 0; + + av_freep(&frag->data); + frag->data_size = 0; + frag->data_bit_padding = 0; +} + +static int cbs_read_fragment_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err, i, j; + + for (i = 0; i < frag->nb_units; i++) { + if (ctx->decompose_unit_types) { + for (j = 0; j < ctx->nb_decompose_unit_types; j++) { + if (ctx->decompose_unit_types[j] == frag->units[i].type) + break; + } + if (j >= ctx->nb_decompose_unit_types) + continue; + } + + err = ctx->codec->read_unit(ctx, &frag->units[i]); + if (err == AVERROR(ENOSYS)) { + av_log(ctx->log_ctx, AV_LOG_WARNING, + "Decomposition unimplemented for unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + } else if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + return err; + } + } + + return 0; +} + +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + frag->data = par->extradata; + frag->data_size = par->extradata_size; + + err = ctx->codec->split_fragment(ctx, frag, 1); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + frag->data = pkt->data; + frag->data_size = pkt->size; + + err = ctx->codec->split_fragment(ctx, frag, 0); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + // (We won't write to this during split.) + frag->data = (uint8_t*)data; + frag->data_size = size; + + err = ctx->codec->split_fragment(ctx, frag, 0); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + + +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err, i; + + for (i = 0; i < frag->nb_units; i++) { + if (!frag->units[i].content) + continue; + + err = ctx->codec->write_unit(ctx, &frag->units[i]); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + return err; + } + } + + err = ctx->codec->assemble_fragment(ctx, frag); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); + return err; + } + + return 0; +} + +int ff_cbs_write_extradata(CodedBitstreamContext *ctx, + AVCodecParameters *par, + CodedBitstreamFragment *frag) +{ + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if (err < 0) + return err; + + av_freep(&par->extradata); + + par->extradata = av_malloc(frag->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!par->extradata) + return AVERROR(ENOMEM); + + memcpy(par->extradata, frag->data, frag->data_size); + memset(par->extradata + frag->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + par->extradata_size = frag->data_size; + + return 0; +} + +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag) +{ + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if (err < 0) + return err; + + err = av_new_packet(pkt, frag->data_size); + if (err < 0) + return err; + + memcpy(pkt->data, frag->data, frag->data_size); + pkt->size = frag->data_size; + + return 0; +} + + +void ff_cbs_trace_header(CodedBitstreamContext *ctx, + const char *name) +{ + if (!ctx->trace_enable) + return; + + av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); +} + +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, + const char *name, const char *bits, + int64_t value) +{ + size_t name_len, bits_len; + int pad; + + if (!ctx->trace_enable) + return; + + av_assert0(value >= INT_MIN && value <= UINT32_MAX); + + name_len = strlen(name); + bits_len = strlen(bits); + + if (name_len + bits_len > 60) + pad = bits_len + 2; + else + pad = 61 - name_len; + + av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n", + position, name, pad, bits, value); +} + +int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) +{ + uint32_t value; + int position; + + av_assert0(width > 0 && width <= 32); + + if (get_bits_left(gbc) < width) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + value = get_bits_long(gbc, width); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + } + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) +{ + av_assert0(width > 0 && width <= 32); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (put_bits_left(pbc) < width) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + if (width < 32) + put_bits(pbc, width, value); + else + put_bits32(pbc, value); + + return 0; +} + + +static int cbs_insert_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) +{ + CodedBitstreamUnit *units; + + units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); + if (!units) + return AVERROR(ENOMEM); + + if (position > 0) + memcpy(units, frag->units, position * sizeof(*units)); + if (position < frag->nb_units) + memcpy(units + position + 1, frag->units + position, + (frag->nb_units - position) * sizeof(*units)); + + memset(units + position, 0, sizeof(*units)); + + av_freep(&frag->units); + frag->units = units; + ++frag->nb_units; + + return 0; +} + +int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content) +{ + int err; + + if (position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + err = cbs_insert_unit(ctx, frag, position); + if (err < 0) + return err; + + frag->units[position].type = type; + frag->units[position].content = content; + frag->units[position].content_external = 1; + + return 0; +} + +int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size) +{ + int err; + + if (position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + err = cbs_insert_unit(ctx, frag, position); + if (err < 0) + return err; + + frag->units[position].type = type; + frag->units[position].data = data; + frag->units[position].data_size = data_size; + + return 0; +} + +int ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) +{ + if (position < 0 || position >= frag->nb_units) + return AVERROR(EINVAL); + + cbs_unit_uninit(ctx, &frag->units[position]); + + --frag->nb_units; + + if (frag->nb_units == 0) { + av_freep(&frag->units); + + } else { + memmove(frag->units + position, + frag->units + position + 1, + (frag->nb_units - position) * sizeof(*frag->units)); + + // Don't bother reallocating the unit array. + } + + return 0; +} diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h new file mode 100644 index 000000000..ff9788061 --- /dev/null +++ b/libavcodec/cbs.h @@ -0,0 +1,312 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CBS_H +#define AVCODEC_CBS_H + +#include +#include + +#include "avcodec.h" + + +/* + * This defines a framework for converting between a coded bitstream + * and structures defining all individual syntax elements found in + * such a stream. + * + * Conversion in both directions is possible. Given a coded bitstream + * (any meaningful fragment), it can be parsed and decomposed into + * syntax elements stored in a set of codec-specific structures. + * Similarly, given a set of those same codec-specific structures the + * syntax elements can be serialised and combined to create a coded + * bitstream. + */ + +struct CodedBitstreamType; + +/** + * The codec-specific type of a bitstream unit. + * + * H.264 / AVC: nal_unit_type + * H.265 / HEVC: nal_unit_type + * MPEG-2: start code value (without prefix) + */ +typedef uint32_t CodedBitstreamUnitType; + +/** + * Coded bitstream unit structure. + * + * A bitstream unit the smallest element of a bitstream which + * is meaningful on its own. For example, an H.264 NAL unit. + * + * See the codec-specific header for the meaning of this for any + * particular codec. + */ +typedef struct CodedBitstreamUnit { + /** + * Codec-specific type of this unit. + */ + CodedBitstreamUnitType type; + + /** + * Pointer to the directly-parsable bitstream form of this unit. + * + * May be NULL if the unit currently only exists in decomposed form. + */ + uint8_t *data; + /** + * The number of bytes in the bitstream (including any padding bits + * in the final byte). + */ + size_t data_size; + /** + * The number of bits which should be ignored in the final byte. + * + * This supports non-byte-aligned bitstreams. + */ + size_t data_bit_padding; + + /** + * Pointer to the decomposed form of this unit. + * + * The type of this structure depends on both the codec and the + * type of this unit. May be NULL if the unit only exists in + * bitstream form. + */ + void *content; + /** + * Whether the content was supplied externally. + * + * If so, it should not be freed when freeing the unit. + */ + int content_external; +} CodedBitstreamUnit; + +/** + * Coded bitstream fragment structure, combining one or more units. + * + * This is any sequence of units. It need not form some greater whole, + * though in many cases it will. For example, an H.264 access unit, + * which is composed of a sequence of H.264 NAL units. + */ +typedef struct CodedBitstreamFragment { + /** + * Pointer to the bitstream form of this fragment. + * + * May be NULL if the fragment only exists as component units. + */ + uint8_t *data; + /** + * The number of bytes in the bitstream. + * + * The number of bytes in the bitstream (including any padding bits + * in the final byte). + */ + size_t data_size; + /** + * The number of bits which should be ignored in the final byte. + */ + size_t data_bit_padding; + + /** + * Number of units in this fragment. + * + * This may be zero if the fragment only exists in bitstream form + * and has not been decomposed. + */ + int nb_units; + /** + * Pointer to an array of units of length nb_units. + * + * Must be NULL if nb_units is zero. + */ + CodedBitstreamUnit *units; +} CodedBitstreamFragment; + +/** + * Context structure for coded bitstream operations. + */ +typedef struct CodedBitstreamContext { + /** + * Logging context to be passed to all av_log() calls associated + * with this context. + */ + void *log_ctx; + + /** + * Internal codec-specific hooks. + */ + const struct CodedBitstreamType *codec; + + /** + * Internal codec-specific data. + * + * This contains any information needed when reading/writing + * bitsteams which will not necessarily be present in a fragment. + * For example, for H.264 it contains all currently visible + * parameter sets - they are required to determine the bitstream + * syntax but need not be present in every access unit. + */ + void *priv_data; + + /** + * Array of unit types which should be decomposed when reading. + * + * Types not in this list will be available in bitstream form only. + * If NULL, all supported types will be decomposed. + */ + CodedBitstreamUnitType *decompose_unit_types; + /** + * Length of the decompose_unit_types array. + */ + int nb_decompose_unit_types; + + /** + * Enable trace output during read/write operations. + */ + int trace_enable; + /** + * Log level to use for trace output. + * + * From AV_LOG_*; defaults to AV_LOG_TRACE. + */ + int trace_level; +} CodedBitstreamContext; + + +/** + * Create and initialise a new context for the given codec. + */ +int ff_cbs_init(CodedBitstreamContext **ctx, + enum AVCodecID codec_id, void *log_ctx); + +/** + * Close a context and free all internal state. + */ +void ff_cbs_close(CodedBitstreamContext **ctx); + + +/** + * Read the extradata bitstream found in codec parameters into a + * fragment, then split into units and decompose. + * + * This also updates the internal state, so will need to be called for + * codecs with extradata to read parameter sets necessary for further + * parsing even if the fragment itself is not desired. + */ +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par); + +/** + * Read the data bitstream from a packet into a fragment, then + * split into units and decompose. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * read following fragments (e.g. parameter sets). + */ +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt); + +/** + * Read a bitstream from a memory region into a fragment, then + * split into units and decompose. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * read following fragments (e.g. parameter sets). + */ +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size); + + +/** + * Write the content of the fragment to its own internal buffer. + * + * Writes the content of all units and then assembles them into a new + * data buffer. When modifying the content of decomposed units, this + * can be used to regenerate the bitstream form of units or the whole + * fragment so that it can be extracted for other use. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * write following fragments (e.g. parameter sets). + */ +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to the extradata in codec parameters. + * + * This replaces any existing extradata in the structure. + */ +int ff_cbs_write_extradata(CodedBitstreamContext *ctx, + AVCodecParameters *par, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to a packet. + */ +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag); + + +/** + * Free all allocated memory in a fragment. + */ +void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + + +/** + * Insert a new unit into a fragment with the given content. + * + * The content structure continues to be owned by the caller, and + * will not be freed when the unit is. + */ +int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content); + +/** + * Insert a new unit into a fragment with the given data bitstream. + * + * The data buffer will be owned by the unit after this operation. + */ +int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size); + +/** + * Delete a unit from a fragment and free all memory it uses. + */ +int ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position); + + +#endif /* AVCODEC_CBS_H */ diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h new file mode 100644 index 000000000..ab7dfd855 --- /dev/null +++ b/libavcodec/cbs_h264.h @@ -0,0 +1,427 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CBS_H264_H +#define AVCODEC_CBS_H264_H + +#include +#include + +#include "cbs_h2645.h" +#include "h264.h" + + +enum { + // This limit is arbitrary - it is sufficient for one message of each + // type plus some repeats, and will therefore easily cover all sane + // streams. However, it is possible to make technically-valid streams + // for which it will fail (for example, by including a large number of + // user-data-unregistered messages). + H264_MAX_SEI_PAYLOADS = 64, +}; + + +typedef struct H264RawNALUnitHeader { + uint8_t forbidden_zero_bit; + uint8_t nal_ref_idc; + uint8_t nal_unit_type; + + uint8_t svc_extension_flag; + uint8_t avc_3d_extension_flag; +} H264RawNALUnitHeader; + +typedef struct H264RawScalingList { + int8_t delta_scale[64]; +} H264RawScalingList; + +typedef struct H264RawHRD { + uint8_t cpb_cnt_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + + uint32_t bit_rate_value_minus1[H264_MAX_CPB_CNT]; + uint32_t cpb_size_value_minus1[H264_MAX_CPB_CNT]; + uint8_t cbr_flag[H264_MAX_CPB_CNT]; + + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + uint8_t time_offset_length; +} H264RawHRD; + +typedef struct H264RawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + + uint8_t timing_info_present_flag; + uint32_t num_units_in_tick; + uint32_t time_scale; + uint8_t fixed_frame_rate_flag; + + uint8_t nal_hrd_parameters_present_flag; + H264RawHRD nal_hrd_parameters; + uint8_t vcl_hrd_parameters_present_flag; + H264RawHRD vcl_hrd_parameters; + uint8_t low_delay_hrd_flag; + + uint8_t pic_struct_present_flag; + + uint8_t bitstream_restriction_flag; + uint8_t motion_vectors_over_pic_boundaries_flag; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_mb_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; + uint8_t max_num_reorder_frames; + uint8_t max_dec_frame_buffering; +} H264RawVUI; + +typedef struct H264RawSPS { + H264RawNALUnitHeader nal_unit_header; + + uint8_t profile_idc; + uint8_t constraint_set0_flag; + uint8_t constraint_set1_flag; + uint8_t constraint_set2_flag; + uint8_t constraint_set3_flag; + uint8_t constraint_set4_flag; + uint8_t constraint_set5_flag; + uint8_t reserved_zero_2bits; + uint8_t level_idc; + + uint8_t seq_parameter_set_id; + + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t qpprime_y_zero_transform_bypass_flag; + + uint8_t seq_scaling_matrix_present_flag; + uint8_t seq_scaling_list_present_flag[12]; + H264RawScalingList scaling_list_4x4[6]; + H264RawScalingList scaling_list_8x8[6]; + + uint8_t log2_max_frame_num_minus4; + uint8_t pic_order_cnt_type; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t delta_pic_order_always_zero_flag; + int32_t offset_for_non_ref_pic; + int32_t offset_for_top_to_bottom_field; + uint8_t num_ref_frames_in_pic_order_cnt_cycle; + int32_t offset_for_ref_frame[256]; + + uint8_t max_num_ref_frames; + uint8_t gaps_in_frame_num_allowed_flag; + + uint16_t pic_width_in_mbs_minus1; + uint16_t pic_height_in_map_units_minus1; + + uint8_t frame_mbs_only_flag; + uint8_t mb_adaptive_frame_field_flag; + uint8_t direct_8x8_inference_flag; + + uint8_t frame_cropping_flag; + uint16_t frame_crop_left_offset; + uint16_t frame_crop_right_offset; + uint16_t frame_crop_top_offset; + uint16_t frame_crop_bottom_offset; + + uint8_t vui_parameters_present_flag; + H264RawVUI vui; +} H264RawSPS; + +typedef struct H264RawSPSExtension { + H264RawNALUnitHeader nal_unit_header; + + uint8_t seq_parameter_set_id; + + uint8_t aux_format_idc; + uint8_t bit_depth_aux_minus8; + uint8_t alpha_incr_flag; + uint16_t alpha_opaque_value; + uint16_t alpha_transparent_value; + + uint8_t additional_extension_flag; +} H264RawSPSExtension; + +typedef struct H264RawPPS { + H264RawNALUnitHeader nal_unit_header; + + uint8_t pic_parameter_set_id; + uint8_t seq_parameter_set_id; + + uint8_t entropy_coding_mode_flag; + uint8_t bottom_field_pic_order_in_frame_present_flag; + + uint8_t num_slice_groups_minus1; + uint8_t slice_group_map_type; + uint16_t run_length_minus1[H264_MAX_SLICE_GROUPS]; + uint16_t top_left[H264_MAX_SLICE_GROUPS]; + uint16_t bottom_right[H264_MAX_SLICE_GROUPS]; + uint8_t slice_group_change_direction_flag; + uint16_t slice_group_change_rate_minus1; + uint16_t pic_size_in_map_units_minus1; + uint8_t slice_group_id[H264_MAX_MB_PIC_SIZE]; + + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_idc; + + int8_t pic_init_qp_minus26; + int8_t pic_init_qs_minus26; + int8_t chroma_qp_index_offset; + + uint8_t deblocking_filter_control_present_flag; + uint8_t constrained_intra_pred_flag; + + uint8_t more_rbsp_data; + + uint8_t redundant_pic_cnt_present_flag; + uint8_t transform_8x8_mode_flag; + + uint8_t pic_scaling_matrix_present_flag; + uint8_t pic_scaling_list_present_flag[12]; + H264RawScalingList scaling_list_4x4[6]; + H264RawScalingList scaling_list_8x8[6]; + + int8_t second_chroma_qp_index_offset; +} H264RawPPS; + +typedef struct H264RawAUD { + H264RawNALUnitHeader nal_unit_header; + + uint8_t primary_pic_type; +} H264RawAUD; + +typedef struct H264RawSEIBufferingPeriod { + uint8_t seq_parameter_set_id; + struct { + uint32_t initial_cpb_removal_delay[H264_MAX_CPB_CNT]; + uint32_t initial_cpb_removal_delay_offset[H264_MAX_CPB_CNT]; + } nal, vcl; +} H264RawSEIBufferingPeriod; + +typedef struct H264RawSEIPicTimestamp { + uint8_t ct_type; + uint8_t nuit_field_based_flag; + uint8_t counting_type; + uint8_t full_timestamp_flag; + uint8_t discontinuity_flag; + uint8_t cnt_dropped_flag; + uint8_t n_frames; + uint8_t seconds_flag; + uint8_t seconds_value; + uint8_t minutes_flag; + uint8_t minutes_value; + uint8_t hours_flag; + uint8_t hours_value; + uint32_t time_offset; +} H264RawSEIPicTimestamp; + +typedef struct H264RawSEIPicTiming { + uint32_t cpb_removal_delay; + uint32_t dpb_output_delay; + uint8_t pic_struct; + uint8_t clock_timestamp_flag[3]; + H264RawSEIPicTimestamp timestamp[3]; +} H264RawSEIPicTiming; + +typedef struct H264RawSEIUserDataRegistered { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension_byte; + uint8_t *data; + size_t data_length; +} H264RawSEIUserDataRegistered; + +typedef struct H264RawSEIUserDataUnregistered { + uint8_t uuid_iso_iec_11578[16]; + uint8_t *data; + size_t data_length; +} H264RawSEIUserDataUnregistered; + +typedef struct H264RawSEIRecoveryPoint { + uint16_t recovery_frame_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; + uint8_t changing_slice_group_idc; +} H264RawSEIRecoveryPoint; + +typedef struct H264RawSEIDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t hor_flip; + uint8_t ver_flip; + uint16_t anticlockwise_rotation; + uint16_t display_orientation_repetition_period; + uint8_t display_orientation_extension_flag; +} H264RawSEIDisplayOrientation; + +typedef struct H264RawSEIPayload { + uint32_t payload_type; + uint32_t payload_size; + union { + H264RawSEIBufferingPeriod buffering_period; + H264RawSEIPicTiming pic_timing; + // H264RawSEIFiller filler -> no fields. + H264RawSEIUserDataRegistered user_data_registered; + H264RawSEIUserDataUnregistered user_data_unregistered; + H264RawSEIRecoveryPoint recovery_point; + H264RawSEIDisplayOrientation display_orientation; + struct { + uint8_t *data; + size_t data_length; + } other; + } payload; +} H264RawSEIPayload; + +typedef struct H264RawSEI { + H264RawNALUnitHeader nal_unit_header; + + H264RawSEIPayload payload[H264_MAX_SEI_PAYLOADS]; + uint8_t payload_count; +} H264RawSEI; + +typedef struct H264RawSliceHeader { + H264RawNALUnitHeader nal_unit_header; + + uint32_t first_mb_in_slice; + uint8_t slice_type; + + uint8_t pic_parameter_set_id; + + uint8_t colour_plane_id; + + uint16_t frame_num; + uint8_t field_pic_flag; + uint8_t bottom_field_flag; + + uint16_t idr_pic_id; + + uint16_t pic_order_cnt_lsb; + int32_t delta_pic_order_cnt_bottom; + int32_t delta_pic_order_cnt[2]; + + uint8_t redundant_pic_cnt; + uint8_t direct_spatial_mv_pred_flag; + + uint8_t num_ref_idx_active_override_flag; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + + uint8_t ref_pic_list_modification_flag_l0; + uint8_t ref_pic_list_modification_flag_l1; + struct { + uint8_t modification_of_pic_nums_idc; + int32_t abs_diff_pic_num_minus1; + uint8_t long_term_pic_num; + } rplm_l0[H264_MAX_RPLM_COUNT], rplm_l1[H264_MAX_RPLM_COUNT]; + + uint8_t luma_log2_weight_denom; + uint8_t chroma_log2_weight_denom; + + uint8_t luma_weight_l0_flag[H264_MAX_REFS]; + int8_t luma_weight_l0[H264_MAX_REFS]; + int8_t luma_offset_l0[H264_MAX_REFS]; + uint8_t chroma_weight_l0_flag[H264_MAX_REFS]; + int8_t chroma_weight_l0[H264_MAX_REFS][2]; + int8_t chroma_offset_l0[H264_MAX_REFS][2]; + + uint8_t luma_weight_l1_flag[H264_MAX_REFS]; + int8_t luma_weight_l1[H264_MAX_REFS]; + int8_t luma_offset_l1[H264_MAX_REFS]; + uint8_t chroma_weight_l1_flag[H264_MAX_REFS]; + int8_t chroma_weight_l1[H264_MAX_REFS][2]; + int8_t chroma_offset_l1[H264_MAX_REFS][2]; + + uint8_t no_output_of_prior_pics_flag; + uint8_t long_term_reference_flag; + + uint8_t adaptive_ref_pic_marking_mode_flag; + struct { + uint8_t memory_management_control_operation; + int32_t difference_of_pic_nums_minus1; + uint8_t long_term_pic_num; + uint8_t long_term_frame_idx; + uint8_t max_long_term_frame_idx_plus1; + } mmco[H264_MAX_MMCO_COUNT]; + + uint8_t cabac_init_idc; + + int8_t slice_qp_delta; + + uint8_t sp_for_switch_flag; + int8_t slice_qs_delta; + + uint8_t disable_deblocking_filter_idc; + int8_t slice_alpha_c0_offset_div2; + int8_t slice_beta_offset_div2; + + uint16_t slice_group_change_cycle; +} H264RawSliceHeader; + +typedef struct H264RawSlice { + H264RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; +} H264RawSlice; + + +typedef struct CodedBitstreamH264Context { + // Reader/writer context in common with the H.265 implementation. + CodedBitstreamH2645Context common; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + H264RawSPS *sps[H264_MAX_SPS_COUNT]; + H264RawPPS *pps[H264_MAX_PPS_COUNT]; + + // The currently active parameter sets. These are updated when any + // NAL unit refers to the relevant parameter set. These pointers + // must also be present in the arrays above. + const H264RawSPS *active_sps; + const H264RawPPS *active_pps; + + // The NAL unit type of the most recent normal slice. This is required + // to be able to read/write auxiliary slices, because IdrPicFlag is + // otherwise unknown. + uint8_t last_slice_nal_unit_type; +} CodedBitstreamH264Context; + + +#endif /* AVCODEC_CBS_H264_H */ diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c new file mode 100644 index 000000000..2f96e4f20 --- /dev/null +++ b/libavcodec/cbs_h2645.c @@ -0,0 +1,1419 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "bytestream.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_h264.h" +#include "cbs_h265.h" +#include "golomb.h" +#include "h264.h" +#include "h264_sei.h" +#include "h2645_parse.h" +#include "hevc.h" + + +static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) +{ + uint32_t value; + int position, i, j; + unsigned int k; + char bits[65]; + + position = get_bits_count(gbc); + + for (i = 0; i < 32; i++) { + if (get_bits_left(gbc) < i + 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + k = get_bits1(gbc); + bits[i] = k ? '1' : '0'; + if (k) + break; + } + if (i >= 32) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at " + "%s: more than 31 zeroes.\n", name); + return AVERROR_INVALIDDATA; + } + value = 1; + for (j = 0; j < i; j++) { + k = get_bits1(gbc); + bits[i + j + 1] = k ? '1' : '0'; + value = value << 1 | k; + } + bits[i + j + 1] = 0; + --value; + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, int32_t *write_to, + int32_t range_min, int32_t range_max) +{ + int32_t value; + int position, i, j; + unsigned int k; + uint32_t v; + char bits[65]; + + position = get_bits_count(gbc); + + for (i = 0; i < 32; i++) { + if (get_bits_left(gbc) < i + 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + k = get_bits1(gbc); + bits[i] = k ? '1' : '0'; + if (k) + break; + } + if (i >= 32) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at " + "%s: more than 31 zeroes.\n", name); + return AVERROR_INVALIDDATA; + } + v = 1; + for (j = 0; j < i; j++) { + k = get_bits1(gbc); + bits[i + j + 1] = k ? '1' : '0'; + v = v << 1 | k; + } + bits[i + j + 1] = 0; + if (v & 1) + value = -(int32_t)(v / 2); + else + value = v / 2; + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) +{ + int len; + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + av_assert0(value != UINT32_MAX); + + len = av_log2(value + 1); + if (put_bits_left(pbc) < 2 * len + 1) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[65]; + int i; + + for (i = 0; i < len; i++) + bits[i] = '0'; + bits[len] = '1'; + for (i = 0; i < len; i++) + bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0'; + bits[len + len + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + put_bits(pbc, len, 0); + if (len + 1 < 32) + put_bits(pbc, len + 1, value + 1); + else + put_bits32(pbc, value + 1); + + return 0; +} + +static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, int32_t value, + int32_t range_min, int32_t range_max) +{ + int len; + uint32_t uvalue; + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + av_assert0(value != INT32_MIN); + + if (value == 0) + uvalue = 0; + else if (value > 0) + uvalue = 2 * (uint32_t)value - 1; + else + uvalue = 2 * (uint32_t)-value; + + len = av_log2(uvalue + 1); + if (put_bits_left(pbc) < 2 * len + 1) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[65]; + int i; + + for (i = 0; i < len; i++) + bits[i] = '0'; + bits[len] = '1'; + for (i = 0; i < len; i++) + bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0'; + bits[len + len + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + put_bits(pbc, len, 0); + if (len + 1 < 32) + put_bits(pbc, len + 1, uvalue + 1); + else + put_bits32(pbc, uvalue + 1); + + return 0; +} + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_H264(rw, name) FUNC_NAME(rw, h264, name) +#define FUNC_H265(rw, name) FUNC_NAME(rw, h265, name) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xu(width, name, var, range_min, range_max) do { \ + uint32_t value = range_min; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max) do { \ + uint32_t value = range_min; \ + CHECK(cbs_read_ue_golomb(ctx, rw, #name, \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max) do { \ + int32_t value = range_min; \ + CHECK(cbs_read_se_golomb(ctx, rw, #name, \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max) +#define flag(name) u(1, name, 0, 1) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) +{ + int bits_left = get_bits_left(gbc); + if (bits_left > 8) + return 1; + if (show_bits(gbc, bits_left) == 1 << (bits_left - 1)) + return 0; + return 1; +} + +#define more_rbsp_data(var) ((var) = cbs_h2645_read_more_rbsp_data(rw)) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + name = av_mallocz(size); \ + if (!name) \ + return AVERROR(ENOMEM); \ + } while (0) + +#define FUNC(name) FUNC_H264(READWRITE, name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H265(READWRITE, name) +#include "cbs_h265_syntax_template.c" +#undef FUNC + +#undef READ +#undef READWRITE +#undef RWContext +#undef xu +#undef xue +#undef xse +#undef u +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef byte_alignment +#undef allocate + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xu(width, name, var, range_min, range_max) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max) do { \ + uint32_t value = var; \ + CHECK(cbs_write_ue_golomb(ctx, rw, #name, \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max) do { \ + int32_t value = var; \ + CHECK(cbs_write_se_golomb(ctx, rw, #name, \ + value, range_min, range_max)); \ + } while (0) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max) +#define flag(name) u(1, name, 0, 1) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_H264(READWRITE, name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H265(READWRITE, name) +#include "cbs_h265_syntax_template.c" +#undef FUNC + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xu +#undef xue +#undef xse +#undef u +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef byte_alignment +#undef allocate + + +static void cbs_h264_free_sei(H264RawSEI *sei) +{ + int i; + for (i = 0; i < sei->payload_count; i++) { + H264RawSEIPayload *payload = &sei->payload[i]; + + switch (payload->payload_type) { + case H264_SEI_TYPE_BUFFERING_PERIOD: + case H264_SEI_TYPE_PIC_TIMING: + case H264_SEI_TYPE_RECOVERY_POINT: + case H264_SEI_TYPE_DISPLAY_ORIENTATION: + break; + case H264_SEI_TYPE_USER_DATA_REGISTERED: + av_freep(&payload->payload.user_data_registered.data); + break; + case H264_SEI_TYPE_USER_DATA_UNREGISTERED: + av_freep(&payload->payload.user_data_unregistered.data); + break; + default: + av_freep(&payload->payload.other.data); + break; + } + } +} + +static void cbs_h264_free_slice(H264RawSlice *slice) +{ + av_freep(&slice->data); +} + +static void cbs_h264_free_nal_unit(CodedBitstreamUnit *unit) +{ + switch (unit->type) { + case H264_NAL_SEI: + cbs_h264_free_sei(unit->content); + break; + case H264_NAL_IDR_SLICE: + case H264_NAL_SLICE: + cbs_h264_free_slice(unit->content); + break; + } + av_freep(&unit->content); +} + +static void cbs_h265_free_nal_unit(CodedBitstreamUnit *unit) +{ + switch (unit->type) { + case HEVC_NAL_VPS: + av_freep(&((H265RawVPS*)unit->content)->extension_data.data); + break; + case HEVC_NAL_SPS: + av_freep(&((H265RawSPS*)unit->content)->extension_data.data); + break; + case HEVC_NAL_PPS: + av_freep(&((H265RawPPS*)unit->content)->extension_data.data); + break; + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + av_freep(&((H265RawSlice*)unit->content)->data); + break; + } + av_freep(&unit->content); +} + +static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const H2645Packet *packet) +{ + int err, i; + + for (i = 0; i < packet->nb_nals; i++) { + const H2645NAL *nal = &packet->nals[i]; + size_t size = nal->size; + uint8_t *data; + + // Remove trailing zeroes. + while (size > 0 && nal->data[size - 1] == 0) + --size; + av_assert0(size > 0); + + data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!data) + return AVERROR(ENOMEM); + memcpy(data, nal->data, size); + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + err = ff_cbs_insert_unit_data(ctx, frag, -1, nal->type, + data, size); + if (err < 0) { + av_freep(&data); + return err; + } + } + + return 0; +} + +static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamH2645Context *priv = ctx->priv_data; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if (frag->data_size == 0) + return 0; + + if (header && frag->data[0] && codec_id == AV_CODEC_ID_H264) { + // AVCC header. + size_t size, start, end; + int i, count, version; + + priv->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 6) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid AVCC header: " + "first byte %u.", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 3); + priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + // SPS array. + count = bytestream2_get_byte(&gbc) & 0x1f; + start = bytestream2_tell(&gbc); + for (i = 0; i < count; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC SPS array.\n"); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + + // PPS array. + count = bytestream2_get_byte(&gbc); + start = bytestream2_tell(&gbc); + for (i = 0; i < count; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC PPS array.\n"); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + + if (bytestream2_get_bytes_left(&gbc) > 0) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "%u bytes left at end of AVCC " + "header.\n", bytestream2_get_bytes_left(&gbc)); + } + + } else if (header && frag->data[0] && codec_id == AV_CODEC_ID_HEVC) { + // HVCC header. + size_t size, start, end; + int i, j, nb_arrays, nal_unit_type, nb_nals, version; + + priv->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 23) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid HVCC header: " + "first byte %u.", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 20); + priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + nb_arrays = bytestream2_get_byte(&gbc); + for (i = 0; i < nb_arrays; i++) { + nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f; + nb_nals = bytestream2_get_be16(&gbc); + + start = bytestream2_tell(&gbc); + for (j = 0; j < nb_nals; j++) { + if (bytestream2_get_bytes_left(&gbc) < 2) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_HEVC, 1); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " + "HVCC array %d (%d NAL units of type %d).\n", + i, nb_nals, nal_unit_type); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + } + + } else { + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + priv->mp4, priv->nal_length_size, + codec_id, 1); + if (err < 0) + return err; + + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + } + + return 0; +} + +#define cbs_h2645_replace_ps(h26n, ps_name, ps_var, id_element) \ +static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ + const H26 ## h26n ## Raw ## ps_name *ps_var) \ +{ \ + CodedBitstreamH26 ## h26n ## Context *priv = ctx->priv_data; \ + unsigned int id = ps_var->id_element; \ + if (id > FF_ARRAY_ELEMS(priv->ps_var)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid " #ps_name \ + " id : %d.\n", id); \ + return AVERROR_INVALIDDATA; \ + } \ + av_freep(&priv->ps_var[id]); \ + priv->ps_var[id] = av_malloc(sizeof(*ps_var)); \ + if (!priv->ps_var[id]) \ + return AVERROR(ENOMEM); \ + memcpy(priv->ps_var[id], ps_var, sizeof(*ps_var)); \ + return 0; \ +} + +cbs_h2645_replace_ps(4, SPS, sps, seq_parameter_set_id) +cbs_h2645_replace_ps(4, PPS, pps, pic_parameter_set_id) +cbs_h2645_replace_ps(5, VPS, vps, vps_video_parameter_set_id) +cbs_h2645_replace_ps(5, SPS, sps, sps_seq_parameter_set_id) +cbs_h2645_replace_ps(5, PPS, pps, pps_pic_parameter_set_id) + +static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + switch (unit->type) { + case H264_NAL_SPS: + { + H264RawSPS *sps; + + sps = av_mallocz(sizeof(*sps)); + if (!sps) + return AVERROR(ENOMEM); + err = cbs_h264_read_sps(ctx, &gbc, sps); + if (err >= 0) + err = cbs_h264_replace_sps(ctx, sps); + if (err < 0) { + av_free(sps); + return err; + } + + unit->content = sps; + } + break; + + case H264_NAL_SPS_EXT: + { + H264RawSPSExtension *sps_ext; + + sps_ext = av_mallocz(sizeof(*sps_ext)); + if (!sps_ext) + return AVERROR(ENOMEM); + err = cbs_h264_read_sps_extension(ctx, &gbc, sps_ext); + if (err < 0) { + av_free(sps_ext); + return err; + } + + unit->content = sps_ext; + } + break; + + case H264_NAL_PPS: + { + H264RawPPS *pps; + + pps = av_mallocz(sizeof(*pps)); + if (!pps) + return AVERROR(ENOMEM); + err = cbs_h264_read_pps(ctx, &gbc, pps); + if (err >= 0) + err = cbs_h264_replace_pps(ctx, pps); + if (err < 0) { + av_free(pps); + return err; + } + + unit->content = pps; + } + break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: + { + H264RawSlice *slice; + int pos, len; + + slice = av_mallocz(sizeof(*slice)); + if (!slice) + return AVERROR(ENOMEM); + err = cbs_h264_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) { + av_free(slice); + return err; + } + + pos = get_bits_count(&gbc); + len = unit->data_size; + if (!unit->data[len - 1]) { + int z; + for (z = 0; z < len && !unit->data[len - z - 1]; z++); + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Deleted %d trailing zeroes " + "from slice data.\n", z); + len -= z; + } + + slice->data_size = len - pos / 8; + slice->data = av_malloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data) { + av_free(slice); + return AVERROR(ENOMEM); + } + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + + unit->content = slice; + } + break; + + case H264_NAL_AUD: + { + H264RawAUD *aud; + + aud = av_mallocz(sizeof(*aud)); + if (!aud) + return AVERROR(ENOMEM); + err = cbs_h264_read_aud(ctx, &gbc, aud); + if (err < 0) { + av_free(aud); + return err; + } + + unit->content = aud; + } + break; + + case H264_NAL_SEI: + { + H264RawSEI *sei; + + sei = av_mallocz(sizeof(*sei)); + if (!sei) + return AVERROR(ENOMEM); + err = cbs_h264_read_sei(ctx, &gbc, sei); + if (err < 0) { + cbs_h264_free_sei(sei); + av_free(sei); + return err; + } + + unit->content = sei; + } + break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + switch (unit->type) { + case HEVC_NAL_VPS: + { + H265RawVPS *vps; + + vps = av_mallocz(sizeof(*vps)); + if (!vps) + return AVERROR(ENOMEM); + err = cbs_h265_read_vps(ctx, &gbc, vps); + if (err >= 0) + err = cbs_h265_replace_vps(ctx, vps); + if (err < 0) { + av_free(vps); + return err; + } + + unit->content = vps; + } + break; + case HEVC_NAL_SPS: + { + H265RawSPS *sps; + + sps = av_mallocz(sizeof(*sps)); + if (!sps) + return AVERROR(ENOMEM); + err = cbs_h265_read_sps(ctx, &gbc, sps); + if (err >= 0) + err = cbs_h265_replace_sps(ctx, sps); + if (err < 0) { + av_free(sps); + return err; + } + + unit->content = sps; + } + break; + + case HEVC_NAL_PPS: + { + H265RawPPS *pps; + + pps = av_mallocz(sizeof(*pps)); + if (!pps) + return AVERROR(ENOMEM); + err = cbs_h265_read_pps(ctx, &gbc, pps); + if (err >= 0) + err = cbs_h265_replace_pps(ctx, pps); + if (err < 0) { + av_free(pps); + return err; + } + + unit->content = pps; + } + break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + { + H265RawSlice *slice; + int pos, len; + + slice = av_mallocz(sizeof(*slice)); + if (!slice) + return AVERROR(ENOMEM); + err = cbs_h265_read_slice_segment_header(ctx, &gbc, &slice->header); + if (err < 0) { + av_free(slice); + return err; + } + + pos = get_bits_count(&gbc); + len = unit->data_size; + if (!unit->data[len - 1]) { + int z; + for (z = 0; z < len && !unit->data[len - z - 1]; z++); + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Deleted %d trailing zeroes " + "from slice data.\n", z); + len -= z; + } + + slice->data_size = len - pos / 8; + slice->data = av_malloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data) { + av_free(slice); + return AVERROR(ENOMEM); + } + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + + unit->content = slice; + } + break; + + case HEVC_NAL_AUD: + { + H265RawAUD *aud; + + aud = av_mallocz(sizeof(*aud)); + if (!aud) + return AVERROR(ENOMEM); + err = cbs_h265_read_aud(ctx, &gbc, aud); + if (err < 0) { + av_free(aud); + return err; + } + + unit->content = aud; + } + break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case H264_NAL_SPS: + { + H264RawSPS *sps = unit->content; + + err = cbs_h264_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, sps); + if (err < 0) + return err; + } + break; + + case H264_NAL_SPS_EXT: + { + H264RawSPSExtension *sps_ext = unit->content; + + err = cbs_h264_write_sps_extension(ctx, pbc, sps_ext); + if (err < 0) + return err; + } + break; + + case H264_NAL_PPS: + { + H264RawPPS *pps = unit->content; + + err = cbs_h264_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, pps); + if (err < 0) + return err; + } + break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: + { + H264RawSlice *slice = unit->content; + GetBitContext gbc; + int bits_left, end, zeroes; + + err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + // Copy in two-byte blocks, but stop before copying the + // rbsp_stop_one_bit in the final byte. + while (get_bits_left(&gbc) > 23) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + end = get_bits(&gbc, bits_left); + + // rbsp_stop_one_bit must be present here. + av_assert0(end); + zeroes = ff_ctz(end); + if (bits_left > zeroes + 1) + put_bits(pbc, bits_left - zeroes - 1, + end >> (zeroes + 1)); + put_bits(pbc, 1, 1); + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } else { + // No slice data - that was just the header. + // (Bitstream may be unaligned!) + } + } + break; + + case H264_NAL_AUD: + { + err = cbs_h264_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_SEI: + { + err = cbs_h264_write_sei(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case HEVC_NAL_VPS: + { + H265RawVPS *vps = unit->content; + + err = cbs_h265_write_vps(ctx, pbc, vps); + if (err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, vps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_SPS: + { + H265RawSPS *sps = unit->content; + + err = cbs_h265_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, sps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_PPS: + { + H265RawPPS *pps = unit->content; + + err = cbs_h265_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, pps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + { + H265RawSlice *slice = unit->content; + GetBitContext gbc; + int bits_left, end, zeroes; + + err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + // Copy in two-byte blocks, but stop before copying the + // rbsp_stop_one_bit in the final byte. + while (get_bits_left(&gbc) > 23) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + end = get_bits(&gbc, bits_left); + + // rbsp_stop_one_bit must be present here. + av_assert0(end); + zeroes = ff_ctz(end); + if (bits_left > zeroes + 1) + put_bits(pbc, bits_left - zeroes - 1, + end >> (zeroes + 1)); + put_bits(pbc, 1, 1); + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } else { + // No slice data - that was just the header. + } + } + break; + + case HEVC_NAL_AUD: + { + err = cbs_h265_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h2645_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamH2645Context *priv = ctx->priv_data; + enum AVCodecID codec_id = ctx->codec->codec_id; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + if (codec_id == AV_CODEC_ID_H264) + err = cbs_h264_write_nal_unit(ctx, unit, &pbc); + else + err = cbs_h265_write_nal_unit(ctx, unit, &pbc); + + if (err == AVERROR(ENOSPC)) { + // Overflow. + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + // Overflow but we didn't notice. + av_assert0(put_bits_count(&pbc) <= 8 * priv->write_buffer_size); + + if (err < 0) { + // Write failed for some other reason. + return err; + } + + if (put_bits_count(&pbc) % 8) + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; + else + unit->data_bit_padding = 0; + + unit->data_size = (put_bits_count(&pbc) + 7) / 8; + flush_put_bits(&pbc); + + err = av_reallocp(&unit->data, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + uint8_t *data; + size_t max_size, dp, sp; + int err, i, zero_run; + + for (i = 0; i < frag->nb_units; i++) { + // Data should already all have been written when we get here. + av_assert0(frag->units[i].data); + } + + max_size = 0; + for (i = 0; i < frag->nb_units; i++) { + // Start code + content with worst-case emulation prevention. + max_size += 3 + frag->units[i].data_size * 3 / 2; + } + + data = av_malloc(max_size); + if (!data) + return AVERROR(ENOMEM); + + dp = 0; + for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + if (unit->data_bit_padding > 0) { + if (i < frag->nb_units - 1) + av_log(ctx->log_ctx, AV_LOG_WARNING, "Probably invalid " + "unaligned padding on non-final NAL unit.\n"); + else + frag->data_bit_padding = unit->data_bit_padding; + } + + if ((ctx->codec->codec_id == AV_CODEC_ID_H264 && + (unit->type == H264_NAL_SPS || + unit->type == H264_NAL_PPS)) || + (ctx->codec->codec_id == AV_CODEC_ID_HEVC && + (unit->type == HEVC_NAL_VPS || + unit->type == HEVC_NAL_SPS || + unit->type == HEVC_NAL_PPS)) || + i == 0 /* (Assume this is the start of an access unit.) */) { + // zero_byte + data[dp++] = 0; + } + // start_code_prefix_one_3bytes + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + zero_run = 0; + for (sp = 0; sp < unit->data_size; sp++) { + if (zero_run < 2) { + if (unit->data[sp] == 0) + ++zero_run; + else + zero_run = 0; + } else { + if ((unit->data[sp] & ~3) == 0) { + // emulation_prevention_three_byte + data[dp++] = 3; + } + zero_run = unit->data[sp] == 0; + } + data[dp++] = unit->data[sp]; + } + } + + av_assert0(dp <= max_size); + err = av_reallocp(&data, dp); + if (err) + return err; + + frag->data = data; + frag->data_size = dp; + + return 0; +} + +static void cbs_h264_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h264->common.read_packet); + + av_freep(&h264->common.write_buffer); + + for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) + av_freep(&h264->sps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) + av_freep(&h264->pps[i]); +} + +static void cbs_h265_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h265->common.read_packet); + + av_freep(&h265->common.write_buffer); + + for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) + av_freep(&h265->vps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) + av_freep(&h265->sps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) + av_freep(&h265->pps[i]); +} + +const CodedBitstreamType ff_cbs_type_h264 = { + .codec_id = AV_CODEC_ID_H264, + + .priv_data_size = sizeof(CodedBitstreamH264Context), + + .split_fragment = &cbs_h2645_split_fragment, + .read_unit = &cbs_h264_read_nal_unit, + .write_unit = &cbs_h2645_write_nal_unit, + .assemble_fragment = &cbs_h2645_assemble_fragment, + + .free_unit = &cbs_h264_free_nal_unit, + .close = &cbs_h264_close, +}; + +const CodedBitstreamType ff_cbs_type_h265 = { + .codec_id = AV_CODEC_ID_HEVC, + + .priv_data_size = sizeof(CodedBitstreamH265Context), + + .split_fragment = &cbs_h2645_split_fragment, + .read_unit = &cbs_h265_read_nal_unit, + .write_unit = &cbs_h2645_write_nal_unit, + .assemble_fragment = &cbs_h2645_assemble_fragment, + + .free_unit = &cbs_h265_free_nal_unit, + .close = &cbs_h265_close, +}; diff --git a/libavutil/opencl_internal.h b/libavcodec/cbs_h2645.h similarity index 56% rename from libavutil/opencl_internal.h rename to libavcodec/cbs_h2645.h index 5cabb7b3e..f4cf65bdd 100644 --- a/libavutil/opencl_internal.h +++ b/libavcodec/cbs_h2645.h @@ -1,8 +1,4 @@ /* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -20,21 +16,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_OPENCL_INTERNAL_H -#define AVUTIL_OPENCL_INTERNAL_H +#ifndef AVCODEC_CBS_H2645_H +#define AVCODEC_CBS_H2645_H -#include "attributes.h" -#include "opencl.h" +#include +#include -#define FF_OPENCL_PARAM_INFO(a) ((void*)(&(a))), (sizeof(a)) +#include "h2645_parse.h" -typedef struct { - cl_kernel kernel; - int param_num; - void *ctx; -} FFOpenclParam; -av_warn_unused_result -int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...); +typedef struct CodedBitstreamH2645Context { + // If set, the stream being read is in MP4 (AVCC/HVCC) format. If not + // set, the stream is assumed to be in annex B format. + int mp4; + // Size in bytes of the NAL length field for MP4 format. + int nal_length_size; + // Packet reader. + H2645Packet read_packet; -#endif /* AVUTIL_OPENCL_INTERNAL_H */ + // Write buffer + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamH2645Context; + + +#endif /* AVCODEC_CBS_H2645_H */ diff --git a/libavcodec/cbs_h264_syntax_template.c b/libavcodec/cbs_h264_syntax_template.c new file mode 100644 index 000000000..2d6027350 --- /dev/null +++ b/libavcodec/cbs_h264_syntax_template.c @@ -0,0 +1,1230 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int one = 1, zero = 0; + xu(1, rbsp_stop_one_bit, one, 1, 1); + while (byte_alignment(rw) != 0) + xu(1, rbsp_alignment_zero_bit, zero, 0, 0); + + return 0; +} + +static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawNALUnitHeader *current, + uint32_t valid_type_mask) +{ + int err; + + u(1, forbidden_zero_bit, 0, 0); + u(2, nal_ref_idc, 0, 3); + u(5, nal_unit_type, 0, 31); + + if (!(1 << current->nal_unit_type & valid_type_mask)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n", + current->nal_unit_type); + return AVERROR_INVALIDDATA; + } + + if (current->nal_unit_type == 14 || + current->nal_unit_type == 20 || + current->nal_unit_type == 21) { + if (current->nal_unit_type != 21) + flag(svc_extension_flag); + else + flag(avc_3d_extension_flag); + + if (current->svc_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SVC not supported.\n"); + return AVERROR_PATCHWELCOME; + + } else if (current->avc_3d_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "3DAVC not supported.\n"); + return AVERROR_PATCHWELCOME; + + } else { + av_log(ctx->log_ctx, AV_LOG_ERROR, "MVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } + } + + return 0; +} + +static int FUNC(scaling_list)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawScalingList *current, + int size_of_scaling_list) +{ + int err, i, scale; + + scale = 8; + for (i = 0; i < size_of_scaling_list; i++) { + xse(delta_scale, current->delta_scale[i], -128, +127); + scale = (scale + current->delta_scale[i] + 256) % 256; + if (scale == 0) + break; + } + + return 0; +} + +static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawHRD *current) +{ + int err, i; + + ue(cpb_cnt_minus1, 0, 31); + u(4, bit_rate_scale, 0, 15); + u(4, cpb_size_scale, 0, 15); + + for (i = 0; i <= current->cpb_cnt_minus1; i++) { + ue(bit_rate_value_minus1[i], 0, UINT32_MAX - 1); + ue(cpb_size_value_minus1[i], 0, UINT32_MAX - 1); + flag(cbr_flag[i]); + } + + u(5, initial_cpb_removal_delay_length_minus1, 0, 31); + u(5, cpb_removal_delay_length_minus1, 0, 31); + u(5, dpb_output_delay_length_minus1, 0, 31); + u(5, time_offset_length, 0, 31); + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawVUI *current, H264RawSPS *sps) +{ + int err; + + flag(aspect_ratio_info_present_flag); + if (current->aspect_ratio_info_present_flag) { + u(8, aspect_ratio_idc, 0, 255); + if (current->aspect_ratio_idc == 255) { + u(16, sar_width, 0, 65535); + u(16, sar_height, 0, 65535); + } + } else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if (current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + + flag(video_signal_type_present_flag); + if (current->video_signal_type_present_flag) { + u(3, video_format, 0, 7); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if (current->colour_description_present_flag) { + u(8, colour_primaries, 0, 255); + u(8, transfer_characteristics, 0, 255); + u(8, matrix_coefficients, 0, 255); + } + } else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + flag(chroma_loc_info_present_flag); + if (current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + flag(timing_info_present_flag); + if (current->timing_info_present_flag) { + u(32, num_units_in_tick, 1, UINT32_MAX); + u(32, time_scale, 1, UINT32_MAX); + flag(fixed_frame_rate_flag); + } else { + infer(fixed_frame_rate_flag, 0); + } + + flag(nal_hrd_parameters_present_flag); + if (current->nal_hrd_parameters_present_flag) + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->nal_hrd_parameters)); + + flag(vcl_hrd_parameters_present_flag); + if (current->vcl_hrd_parameters_present_flag) + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->vcl_hrd_parameters)); + + if (current->nal_hrd_parameters_present_flag || + current->vcl_hrd_parameters_present_flag) + flag(low_delay_hrd_flag); + else + infer(low_delay_hrd_flag, 1 - current->fixed_frame_rate_flag); + + flag(pic_struct_present_flag); + + flag(bitstream_restriction_flag); + if (current->bitstream_restriction_flag) { + flag(motion_vectors_over_pic_boundaries_flag); + ue(max_bytes_per_pic_denom, 0, 16); + ue(max_bits_per_mb_denom, 0, 16); + ue(log2_max_mv_length_horizontal, 0, 16); + ue(log2_max_mv_length_vertical, 0, 16); + ue(max_num_reorder_frames, 0, H264_MAX_DPB_FRAMES); + ue(max_dec_frame_buffering, 0, H264_MAX_DPB_FRAMES); + } else { + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_mb_denom, 1); + infer(log2_max_mv_length_horizontal, 16); + infer(log2_max_mv_length_vertical, 16); + + if ((sps->profile_idc == 44 || sps->profile_idc == 86 || + sps->profile_idc == 110 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244) && + sps->constraint_set3_flag) { + infer(max_num_reorder_frames, 0); + infer(max_dec_frame_buffering, 0); + } else { + infer(max_num_reorder_frames, H264_MAX_DPB_FRAMES); + infer(max_dec_frame_buffering, H264_MAX_DPB_FRAMES); + } + } + + return 0; +} + +static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSPS *current) +{ + int err, i; + + HEADER("Sequence Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SPS)); + + u(8, profile_idc, 0, 255); + + flag(constraint_set0_flag); + flag(constraint_set1_flag); + flag(constraint_set2_flag); + flag(constraint_set3_flag); + flag(constraint_set4_flag); + flag(constraint_set5_flag); + + u(2, reserved_zero_2bits, 0, 0); + + u(8, level_idc, 0, 255); + + ue(seq_parameter_set_id, 0, 31); + + if (current->profile_idc == 100 || current->profile_idc == 110 || + current->profile_idc == 122 || current->profile_idc == 244 || + current->profile_idc == 44 || current->profile_idc == 83 || + current->profile_idc == 86 || current->profile_idc == 118 || + current->profile_idc == 128 || current->profile_idc == 138) { + ue(chroma_format_idc, 0, 3); + + if (current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); + + ue(bit_depth_luma_minus8, 0, 6); + ue(bit_depth_chroma_minus8, 0, 6); + + flag(qpprime_y_zero_transform_bypass_flag); + + flag(seq_scaling_matrix_present_flag); + if (current->seq_scaling_matrix_present_flag) { + for (i = 0; i < ((current->chroma_format_idc != 3) ? 8 : 12); i++) { + flag(seq_scaling_list_present_flag[i]); + if (current->seq_scaling_list_present_flag[i]) { + if (i < 6) + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_4x4[i], + 16)); + else + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_8x8[i - 6], + 64)); + } + } + } + } else { + infer(chroma_format_idc, current->profile_idc == 183 ? 0 : 1); + + infer(separate_colour_plane_flag, 0); + infer(bit_depth_luma_minus8, 0); + infer(bit_depth_chroma_minus8, 0); + } + + ue(log2_max_frame_num_minus4, 0, 12); + ue(pic_order_cnt_type, 0, 2); + + if (current->pic_order_cnt_type == 0) { + ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); + } else if (current->pic_order_cnt_type == 1) { + flag(delta_pic_order_always_zero_flag); + se(offset_for_non_ref_pic, INT32_MIN + 1, INT32_MAX); + se(offset_for_top_to_bottom_field, INT32_MIN + 1, INT32_MAX); + ue(num_ref_frames_in_pic_order_cnt_cycle, 0, 255); + + for (i = 0; i < current->num_ref_frames_in_pic_order_cnt_cycle; i++) + se(offset_for_ref_frame[i], INT32_MIN + 1, INT32_MAX); + } + + ue(max_num_ref_frames, 0, H264_MAX_DPB_FRAMES); + flag(gaps_in_frame_num_allowed_flag); + + ue(pic_width_in_mbs_minus1, 0, H264_MAX_MB_WIDTH); + ue(pic_height_in_map_units_minus1, 0, H264_MAX_MB_HEIGHT); + + flag(frame_mbs_only_flag); + if (!current->frame_mbs_only_flag) + flag(mb_adaptive_frame_field_flag); + + flag(direct_8x8_inference_flag); + + flag(frame_cropping_flag); + if (current->frame_cropping_flag) { + ue(frame_crop_left_offset, 0, H264_MAX_WIDTH); + ue(frame_crop_right_offset, 0, H264_MAX_WIDTH); + ue(frame_crop_top_offset, 0, H264_MAX_HEIGHT); + ue(frame_crop_bottom_offset, 0, H264_MAX_HEIGHT); + } + + flag(vui_parameters_present_flag); + if (current->vui_parameters_present_flag) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(sps_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSPSExtension *current) +{ + int err; + + HEADER("Sequence Parameter Set Extension"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SPS_EXT)); + + ue(seq_parameter_set_id, 0, 31); + + ue(aux_format_idc, 0, 3); + + if (current->aux_format_idc != 0) { + int bits; + + ue(bit_depth_aux_minus8, 0, 4); + flag(alpha_incr_flag); + + bits = current->bit_depth_aux_minus8 + 9; + u(bits, alpha_opaque_value, 0, (1 << bits) - 1); + u(bits, alpha_transparent_value, 0, (1 << bits) - 1); + } + + flag(additional_extension_flag); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawPPS *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err, i; + + HEADER("Picture Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_PPS)); + + ue(pic_parameter_set_id, 0, 255); + ue(seq_parameter_set_id, 0, 31); + + sps = h264->sps[current->seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + + flag(entropy_coding_mode_flag); + flag(bottom_field_pic_order_in_frame_present_flag); + + ue(num_slice_groups_minus1, 0, 7); + if (current->num_slice_groups_minus1 > 0) { + unsigned int pic_size; + int iGroup; + + pic_size = (sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1); + + ue(slice_group_map_type, 0, 6); + + if (current->slice_group_map_type == 0) { + for (iGroup = 0; iGroup <= current->num_slice_groups_minus1; iGroup++) + ue(run_length_minus1[iGroup], 0, pic_size - 1); + + } else if (current->slice_group_map_type == 2) { + for (iGroup = 0; iGroup < current->num_slice_groups_minus1; iGroup++) { + ue(top_left[iGroup], 0, pic_size - 1); + ue(bottom_right[iGroup], current->top_left[iGroup], pic_size - 1); + } + } else if (current->slice_group_map_type == 3 || + current->slice_group_map_type == 4 || + current->slice_group_map_type == 5) { + flag(slice_group_change_direction_flag); + ue(slice_group_change_rate_minus1, 0, pic_size - 1); + } else if (current->slice_group_map_type == 6) { + ue(pic_size_in_map_units_minus1, pic_size - 1, pic_size - 1); + for (i = 0; i <= current->pic_size_in_map_units_minus1; i++) + u(av_log2(2 * current->num_slice_groups_minus1 + 1), + slice_group_id[i], 0, current->num_slice_groups_minus1); + } + } + + ue(num_ref_idx_l0_default_active_minus1, 0, 31); + ue(num_ref_idx_l1_default_active_minus1, 0, 31); + + flag(weighted_pred_flag); + u(2, weighted_bipred_idc, 0, 2); + + se(pic_init_qp_minus26, -26 - 6 * sps->bit_depth_luma_minus8, +25); + se(pic_init_qs_minus26, -26, +25); + se(chroma_qp_index_offset, -12, +12); + + flag(deblocking_filter_control_present_flag); + flag(constrained_intra_pred_flag); + flag(redundant_pic_cnt_present_flag); + + if (more_rbsp_data(current->more_rbsp_data)) + { + flag(transform_8x8_mode_flag); + + flag(pic_scaling_matrix_present_flag); + if (current->pic_scaling_matrix_present_flag) { + for (i = 0; i < 6 + (((sps->chroma_format_idc != 3) ? 2 : 6) * + current->transform_8x8_mode_flag); i++) { + flag(pic_scaling_list_present_flag[i]); + if (current->pic_scaling_list_present_flag[i]) { + if (i < 6) + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_4x4[i], + 16)); + else + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_8x8[i - 6], + 64)); + } + } + } + + se(second_chroma_qp_index_offset, -12, +12); + } else { + infer(transform_8x8_mode_flag, 0); + infer(pic_scaling_matrix_present_flag, 0); + infer(second_chroma_qp_index_offset, current->chroma_qp_index_offset); + } + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIBufferingPeriod *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err, i, length; + + ue(seq_parameter_set_id, 0, 31); + + sps = h264->sps[current->seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_sps = sps; + + if (sps->vui.nal_hrd_parameters_present_flag) { + for (i = 0; i <= sps->vui.nal_hrd_parameters.cpb_cnt_minus1; i++) { + length = sps->vui.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; + xu(length, initial_cpb_removal_delay[SchedSelIdx], + current->nal.initial_cpb_removal_delay[i], + 0, (1 << (uint64_t)length) - 1); + xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], + current->nal.initial_cpb_removal_delay_offset[i], + 0, (1 << (uint64_t)length) - 1); + } + } + + if (sps->vui.vcl_hrd_parameters_present_flag) { + for (i = 0; i <= sps->vui.vcl_hrd_parameters.cpb_cnt_minus1; i++) { + length = sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; + xu(length, initial_cpb_removal_delay[SchedSelIdx], + current->vcl.initial_cpb_removal_delay[i], + 0, (1 << (uint64_t)length) - 1); + xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], + current->vcl.initial_cpb_removal_delay_offset[i], + 0, (1 << (uint64_t)length) - 1); + } + } + + return 0; +} + +static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPicTimestamp *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + uint8_t time_offset_length; + int err; + + u(2, ct_type, 0, 2); + flag(nuit_field_based_flag); + u(5, counting_type, 0, 6); + flag(full_timestamp_flag); + flag(discontinuity_flag); + flag(cnt_dropped_flag); + u(8, n_frames, 0, 255); + if (current->full_timestamp_flag) { + u(6, seconds_value, 0, 59); + u(6, minutes_value, 0, 59); + u(5, hours_value, 0, 23); + } else { + flag(seconds_flag); + if (current->seconds_flag) { + u(6, seconds_value, 0, 59); + flag(minutes_flag); + if (current->minutes_flag) { + u(6, minutes_value, 0, 59); + flag(hours_flag); + if (current->hours_flag) + u(5, hours_value, 0, 23); + } + } + } + + sps = h264->active_sps; + if (sps->vui.nal_hrd_parameters_present_flag) + time_offset_length = sps->vui.nal_hrd_parameters.time_offset_length; + else if (sps->vui.vcl_hrd_parameters_present_flag) + time_offset_length = sps->vui.vcl_hrd_parameters.time_offset_length; + else + time_offset_length = 24; + + if (time_offset_length > 0) + u(time_offset_length, time_offset, + 0, (1 << (uint64_t)time_offset_length) - 1); + else + infer(time_offset, 0); + + return 0; +} + +static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPicTiming *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err; + + sps = h264->active_sps; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + if (sps->vui.nal_hrd_parameters_present_flag || + sps->vui.vcl_hrd_parameters_present_flag) { + const H264RawHRD *hrd; + + if (sps->vui.nal_hrd_parameters_present_flag) + hrd = &sps->vui.nal_hrd_parameters; + else if (sps->vui.vcl_hrd_parameters_present_flag) + hrd = &sps->vui.vcl_hrd_parameters; + else { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No HRD parameters for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + u(hrd->cpb_removal_delay_length_minus1 + 1, cpb_removal_delay, + 0, (1 << (uint64_t)hrd->cpb_removal_delay_length_minus1) + 1); + u(hrd->dpb_output_delay_length_minus1 + 1, dpb_output_delay, + 0, (1 << (uint64_t)hrd->dpb_output_delay_length_minus1) + 1); + } + + if (sps->vui.pic_struct_present_flag) { + static const int num_clock_ts[9] = { + 1, 1, 1, 2, 2, 3, 3, 2, 3 + }; + int i; + + u(4, pic_struct, 0, 8); + if (current->pic_struct > 8) + return AVERROR_INVALIDDATA; + + for (i = 0; i < num_clock_ts[current->pic_struct]; i++) { + flag(clock_timestamp_flag[i]); + if (current->clock_timestamp_flag[i]) + CHECK(FUNC(sei_pic_timestamp)(ctx, rw, ¤t->timestamp[i])); + } + } + + return 0; +} + +static int FUNC(sei_user_data_registered)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIUserDataRegistered *current, + uint32_t *payload_size) +{ + int err, i, j; + + u(8, itu_t_t35_country_code, 0x00, 0xff); + if (current->itu_t_t35_country_code != 0xff) + i = 1; + else { + u(8, itu_t_t35_country_code_extension_byte, 0x00, 0xff); + i = 2; + } + +#ifdef READ + if (*payload_size < i) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data registered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = *payload_size - i; +#else + *payload_size = i + current->data_length; +#endif + + allocate(current->data, current->data_length); + for (j = 0; j < current->data_length; j++) + xu(8, itu_t_t35_payload_byte, current->data[j], 0x00, 0xff); + + return 0; +} + +static int FUNC(sei_user_data_unregistered)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIUserDataUnregistered *current, + uint32_t *payload_size) +{ + int err, i; + +#ifdef READ + if (*payload_size < 16) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data unregistered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = *payload_size - 16; +#else + *payload_size = 16 + current->data_length; +#endif + + for (i = 0; i < 16; i++) { + xu(8, uuid_iso_iec_11578, + current->uuid_iso_iec_11578[i], 0x00, 0xff); + } + + allocate(current->data, current->data_length); + + for (i = 0; i < current->data_length; i++) + xu(8, user_data_payload_byte, current->data[i], 0x00, 0xff); + + return 0; +} + +static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIRecoveryPoint *current) +{ + int err; + + ue(recovery_frame_cnt, 0, 65535); + flag(exact_match_flag); + flag(broken_link_flag); + u(2, changing_slice_group_idc, 0, 2); + + return 0; +} + +static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIDisplayOrientation *current) +{ + int err; + + flag(display_orientation_cancel_flag); + if (!current->display_orientation_cancel_flag) { + flag(hor_flip); + flag(ver_flip); + u(16, anticlockwise_rotation, 0, 65535); + ue(display_orientation_repetition_period, 0, 16384); + flag(display_orientation_extension_flag); + } + + return 0; +} + +static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPayload *current) +{ + int err, i; + int start_position, end_position; + +#ifdef READ + start_position = get_bits_count(rw); +#else + start_position = put_bits_count(rw); +#endif + + switch (current->payload_type) { + case H264_SEI_TYPE_BUFFERING_PERIOD: + CHECK(FUNC(sei_buffering_period) + (ctx, rw, ¤t->payload.buffering_period)); + break; + case H264_SEI_TYPE_PIC_TIMING: + CHECK(FUNC(sei_pic_timing) + (ctx, rw, ¤t->payload.pic_timing)); + break; + case H264_SEI_TYPE_FILLER_PAYLOAD: + { + av_unused int ff_byte = 0xff; + for (i = 0; i < current->payload_size; i++) + xu(8, ff_byte, ff_byte, 0xff, 0xff); + } + break; + case H264_SEI_TYPE_USER_DATA_REGISTERED: + CHECK(FUNC(sei_user_data_registered) + (ctx, rw, ¤t->payload.user_data_registered, ¤t->payload_size)); + break; + case H264_SEI_TYPE_USER_DATA_UNREGISTERED: + CHECK(FUNC(sei_user_data_unregistered) + (ctx, rw, ¤t->payload.user_data_unregistered, ¤t->payload_size)); + break; + case H264_SEI_TYPE_RECOVERY_POINT: + CHECK(FUNC(sei_recovery_point) + (ctx, rw, ¤t->payload.recovery_point)); + break; + case H264_SEI_TYPE_DISPLAY_ORIENTATION: + CHECK(FUNC(sei_display_orientation) + (ctx, rw, ¤t->payload.display_orientation)); + break; + default: + { + allocate(current->payload.other.data, current->payload_size); + for (i = 0; i < current->payload_size; i++) + xu(8, payload_byte, current->payload.other.data[i], 0, 255); + } + } + + if (byte_alignment(rw)) { + av_unused int one = 1, zero = 0; + xu(1, bit_equal_to_one, one, 1, 1); + while (byte_alignment(rw)) + xu(1, bit_equal_to_zero, zero, 0, 0); + } + +#ifdef READ + end_position = get_bits_count(rw); + if (end_position < start_position + 8 * current->payload_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Incorrect SEI payload length: " + "header %"PRIu32" bits, actually %d bits.\n", + 8 * current->payload_size, + end_position - start_position); + return AVERROR_INVALIDDATA; + } +#else + end_position = put_bits_count(rw); + current->payload_size = (end_position - start_position) / 8; +#endif + + return 0; +} + +static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEI *current) +{ + int err, k; + + HEADER("Supplemental Enhancement Information"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SEI)); + +#ifdef READ + for (k = 0; k < H264_MAX_SEI_PAYLOADS; k++) { + uint32_t payload_type = 0; + uint32_t payload_size = 0; + uint32_t tmp; + + while (show_bits(rw, 8) == 0xff) { + xu(8, ff_byte, tmp, 0xff, 0xff); + payload_type += 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254); + payload_type += tmp; + + while (show_bits(rw, 8) == 0xff) { + xu(8, ff_byte, tmp, 0xff, 0xff); + payload_size += 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254); + payload_size += tmp; + + current->payload[k].payload_type = payload_type; + current->payload[k].payload_size = payload_size; + + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k])); + + if (!cbs_h2645_read_more_rbsp_data(rw)) + break; + } + if (k >= H264_MAX_SEI_PAYLOADS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in " + "SEI message: found %d.\n", k); + return AVERROR_INVALIDDATA; + } + current->payload_count = k + 1; +#else + for (k = 0; k < current->payload_count; k++) { + PutBitContext start_state; + uint32_t tmp; + int need_size, i; + + // Somewhat clumsy: we write the payload twice when + // we don't know the size in advance. This will mess + // with trace output, but is otherwise harmless. + start_state = *rw; + need_size = !current->payload[k].payload_size; + for (i = 0; i < 1 + need_size; i++) { + *rw = start_state; + + tmp = current->payload[k].payload_type; + while (tmp >= 255) { + xu(8, ff_byte, 0xff, 0xff, 0xff); + tmp -= 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254); + + tmp = current->payload[k].payload_size; + while (tmp >= 255) { + xu(8, ff_byte, 0xff, 0xff, 0xff); + tmp -= 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254); + + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k])); + } + } +#endif + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawAUD *current) +{ + int err; + + HEADER("Access Unit Delimiter"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_AUD)); + + u(3, primary_pic_type, 0, 7); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int err, i, mopn; + + if (current->slice_type % 5 != 2 && + current->slice_type % 5 != 4) { + flag(ref_pic_list_modification_flag_l0); + if (current->ref_pic_list_modification_flag_l0) { + for (i = 0; i < H264_MAX_RPLM_COUNT; i++) { + xue(modification_of_pic_nums_idc, + current->rplm_l0[i].modification_of_pic_nums_idc, 0, 3); + + mopn = current->rplm_l0[i].modification_of_pic_nums_idc; + if (mopn == 3) + break; + + if (mopn == 0 || mopn == 1) + xue(abs_diff_pic_num_minus1, + current->rplm_l0[i].abs_diff_pic_num_minus1, + 0, (1 + current->field_pic_flag) * + (1 << (sps->log2_max_frame_num_minus4 + 4))); + else if (mopn == 2) + xue(long_term_pic_num, + current->rplm_l0[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1); + } + } + } + + if (current->slice_type % 5 == 1) { + flag(ref_pic_list_modification_flag_l1); + if (current->ref_pic_list_modification_flag_l1) { + for (i = 0; i < H264_MAX_RPLM_COUNT; i++) { + xue(modification_of_pic_nums_idc, + current->rplm_l1[i].modification_of_pic_nums_idc, 0, 3); + + mopn = current->rplm_l1[i].modification_of_pic_nums_idc; + if (mopn == 3) + break; + + if (mopn == 0 || mopn == 1) + xue(abs_diff_pic_num_minus1, + current->rplm_l1[i].abs_diff_pic_num_minus1, + 0, (1 + current->field_pic_flag) * + (1 << (sps->log2_max_frame_num_minus4 + 4))); + else if (mopn == 2) + xue(long_term_pic_num, + current->rplm_l1[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1); + } + } + } + + return 0; +} + +static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int chroma; + int err, i, j; + + ue(luma_log2_weight_denom, 0, 7); + + chroma = !sps->separate_colour_plane_flag && sps->chroma_format_idc != 0; + if (chroma) + ue(chroma_log2_weight_denom, 0, 7); + + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + flag(luma_weight_l0_flag[i]); + if (current->luma_weight_l0_flag[i]) { + se(luma_weight_l0[i], -128, +127); + se(luma_offset_l0[i], -128, +127); + } + if (chroma) { + flag(chroma_weight_l0_flag[i]); + if (current->chroma_weight_l0_flag[i]) { + for (j = 0; j < 2; j++) { + se(chroma_weight_l0[i][j], -128, +127); + se(chroma_offset_l0[i][j], -128, +127); + } + } + } + } + + if (current->slice_type % 5 == 1) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + flag(luma_weight_l1_flag[i]); + if (current->luma_weight_l1_flag[i]) { + se(luma_weight_l1[i], -128, +127); + se(luma_offset_l1[i], -128, +127); + } + if (chroma) { + flag(chroma_weight_l1_flag[i]); + if (current->chroma_weight_l1_flag[i]) { + for (j = 0; j < 2; j++) { + se(chroma_weight_l1[i][j], -128, +127); + se(chroma_offset_l1[i][j], -128, +127); + } + } + } + } + } + + return 0; +} + +static int FUNC(dec_ref_pic_marking)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current, int idr_pic_flag) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int err, i; + uint32_t mmco; + + if (idr_pic_flag) { + flag(no_output_of_prior_pics_flag); + flag(long_term_reference_flag); + } else { + flag(adaptive_ref_pic_marking_mode_flag); + if (current->adaptive_ref_pic_marking_mode_flag) { + for (i = 0; i < H264_MAX_MMCO_COUNT; i++) { + xue(memory_management_control_operation, + current->mmco[i].memory_management_control_operation, + 0, 6); + + mmco = current->mmco[i].memory_management_control_operation; + if (mmco == 0) + break; + + if (mmco == 1 || mmco == 3) + xue(difference_of_pic_nums_minus1, + current->mmco[i].difference_of_pic_nums_minus1, + 0, INT32_MAX); + if (mmco == 2) + xue(long_term_pic_num, + current->mmco[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1); + if (mmco == 3 || mmco == 6) + xue(long_term_frame_idx, + current->mmco[i].long_term_frame_idx, + 0, sps->max_num_ref_frames - 1); + if (mmco == 4) + xue(max_long_term_frame_idx_plus1, + current->mmco[i].max_long_term_frame_idx_plus1, + 0, sps->max_num_ref_frames); + } + if (i == H264_MAX_MMCO_COUNT) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many " + "memory management control operations.\n"); + return AVERROR_INVALIDDATA; + } + } + } + + return 0; +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + const H264RawPPS *pps; + int err; + int idr_pic_flag; + int slice_type_i, slice_type_p, slice_type_b; + int slice_type_si, slice_type_sp; + + HEADER("Slice Header"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SLICE | + 1 << H264_NAL_IDR_SLICE | + 1 << H264_NAL_AUXILIARY_SLICE)); + + if (current->nal_unit_header.nal_unit_type == H264_NAL_AUXILIARY_SLICE) { + if (!h264->last_slice_nal_unit_type) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Auxiliary slice " + "is not decodable without the main picture " + "in the same access unit.\n"); + return AVERROR_INVALIDDATA; + } + } else { + h264->last_slice_nal_unit_type = + current->nal_unit_header.nal_unit_type; + } + idr_pic_flag = h264->last_slice_nal_unit_type == H264_NAL_IDR_SLICE; + + ue(first_mb_in_slice, 0, H264_MAX_MB_PIC_SIZE - 1); + ue(slice_type, 0, 9); + + slice_type_i = current->slice_type % 5 == 2; + slice_type_p = current->slice_type % 5 == 0; + slice_type_b = current->slice_type % 5 == 1; + slice_type_si = current->slice_type % 5 == 4; + slice_type_sp = current->slice_type % 5 == 3; + + if (idr_pic_flag && !(slice_type_i || slice_type_si)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid slice type %d " + "for IDR picture.\n", current->slice_type); + return AVERROR_INVALIDDATA; + } + + ue(pic_parameter_set_id, 0, 255); + + pps = h264->pps[current->pic_parameter_set_id]; + if (!pps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "PPS id %d not available.\n", + current->pic_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_pps = pps; + + sps = h264->sps[pps->seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + pps->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_sps = sps; + + if (sps->separate_colour_plane_flag) + u(2, colour_plane_id, 0, 2); + + u(sps->log2_max_frame_num_minus4 + 4, frame_num, + 0, (1 << (sps->log2_max_frame_num_minus4 + 4)) - 1); + + if (!sps->frame_mbs_only_flag) { + flag(field_pic_flag); + if (current->field_pic_flag) + flag(bottom_field_flag); + else + infer(bottom_field_flag, 0); + } else { + infer(field_pic_flag, 0); + infer(bottom_field_flag, 0); + } + + if (idr_pic_flag) + ue(idr_pic_id, 0, 65535); + + if (sps->pic_order_cnt_type == 0) { + u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, pic_order_cnt_lsb, + 0, (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1); + if (pps->bottom_field_pic_order_in_frame_present_flag && + !current->field_pic_flag) + se(delta_pic_order_cnt_bottom, INT32_MIN + 1, INT32_MAX); + + } else if (sps->pic_order_cnt_type == 1) { + if (!sps->delta_pic_order_always_zero_flag) { + se(delta_pic_order_cnt[0], INT32_MIN + 1, INT32_MAX); + if (pps->bottom_field_pic_order_in_frame_present_flag && + !current->field_pic_flag) + se(delta_pic_order_cnt[1], INT32_MIN + 1, INT32_MAX); + else + infer(delta_pic_order_cnt[1], 0); + } else { + infer(delta_pic_order_cnt[0], 0); + infer(delta_pic_order_cnt[1], 0); + } + } + + if (pps->redundant_pic_cnt_present_flag) + ue(redundant_pic_cnt, 0, 127); + + if (slice_type_b) + flag(direct_spatial_mv_pred_flag); + + if (slice_type_p || slice_type_sp || slice_type_b) { + flag(num_ref_idx_active_override_flag); + if (current->num_ref_idx_active_override_flag) { + ue(num_ref_idx_l0_active_minus1, 0, 31); + if (slice_type_b) + ue(num_ref_idx_l1_active_minus1, 0, 31); + } else { + infer(num_ref_idx_l0_active_minus1, + pps->num_ref_idx_l0_default_active_minus1); + infer(num_ref_idx_l1_active_minus1, + pps->num_ref_idx_l1_default_active_minus1); + } + } + + if (current->nal_unit_header.nal_unit_type == 20 || + current->nal_unit_header.nal_unit_type == 21) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "MVC / 3DAVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } else { + CHECK(FUNC(ref_pic_list_modification)(ctx, rw, current)); + } + + if ((pps->weighted_pred_flag && (slice_type_p || slice_type_sp)) || + (pps->weighted_bipred_idc == 1 && slice_type_b)) { + CHECK(FUNC(pred_weight_table)(ctx, rw, current)); + } + + if (current->nal_unit_header.nal_ref_idc != 0) { + CHECK(FUNC(dec_ref_pic_marking)(ctx, rw, current, idr_pic_flag)); + } + + if (pps->entropy_coding_mode_flag && + !slice_type_i && !slice_type_si) { + ue(cabac_init_idc, 0, 2); + } + + se(slice_qp_delta, - 51 - 6 * sps->bit_depth_luma_minus8, + + 51 + 6 * sps->bit_depth_luma_minus8); + if (slice_type_sp || slice_type_si) { + if (slice_type_sp) + flag(sp_for_switch_flag); + se(slice_qs_delta, -51, +51); + } + + if (pps->deblocking_filter_control_present_flag) { + ue(disable_deblocking_filter_idc, 0, 2); + if (current->disable_deblocking_filter_idc != 1) { + se(slice_alpha_c0_offset_div2, -6, +6); + se(slice_beta_offset_div2, -6, +6); + } else { + infer(slice_alpha_c0_offset_div2, 0); + infer(slice_beta_offset_div2, 0); + } + } else { + infer(disable_deblocking_filter_idc, 0); + infer(slice_alpha_c0_offset_div2, 0); + infer(slice_beta_offset_div2, 0); + } + + if (pps->num_slice_groups_minus1 > 0 && + pps->slice_group_map_type >= 3 && + pps->slice_group_map_type <= 5) { + unsigned int pic_size, max, bits; + + pic_size = (sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1); + max = (pic_size + pps->slice_group_change_rate_minus1) / + (pps->slice_group_change_rate_minus1 + 1); + bits = av_log2(2 * max - 1); + + u(bits, slice_group_change_cycle, 0, max); + } + + if (pps->entropy_coding_mode_flag) { + av_unused int one = 1; + while (byte_alignment(rw)) + xu(1, cabac_alignment_one_bit, one, 1, 1); + } + + return 0; +} diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h new file mode 100644 index 000000000..b4777cf6b --- /dev/null +++ b/libavcodec/cbs_h265.h @@ -0,0 +1,537 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CBS_H265_H +#define AVCODEC_CBS_H265_H + +#include +#include + +#include "cbs_h2645.h" +#include "hevc.h" + + +typedef struct H265RawNALUnitHeader { + uint8_t forbidden_zero_bit; + uint8_t nal_unit_type; + uint8_t nuh_layer_id; + uint8_t nuh_temporal_id_plus1; +} H265RawNALUnitHeader; + +typedef struct H265RawProfileTierLevel { + uint8_t general_profile_space; + uint8_t general_tier_flag; + uint8_t general_profile_idc; + + uint8_t general_profile_compatibility_flag[32]; + + uint8_t general_progressive_source_flag; + uint8_t general_interlaced_source_flag; + uint8_t general_non_packed_constraint_flag; + uint8_t general_frame_only_constraint_flag; + + uint8_t general_max_12bit_constraint_flag; + uint8_t general_max_10bit_constraint_flag; + uint8_t general_max_8bit_constraint_flag; + uint8_t general_max_422chroma_constraint_flag; + uint8_t general_max_420chroma_constraint_flag; + uint8_t general_max_monochrome_constraint_flag; + uint8_t general_intra_constraint_flag; + uint8_t general_one_picture_only_constraint_flag; + uint8_t general_lower_bit_rate_constraint_flag; + uint8_t general_max_14bit_constraint_flag; + + uint8_t general_inbld_flag; + + uint8_t general_level_idc; + + uint8_t sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; + + // TODO: much of that again for each sub-layer. +} H265RawProfileTierLevel; + +typedef struct H265RawSubLayerHRDParameters { + uint32_t bit_rate_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t cpb_size_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t cpb_size_du_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t bit_rate_du_value_minus1[HEVC_MAX_CPB_CNT]; + uint8_t cbr_flag[HEVC_MAX_CPB_CNT]; +} H265RawSubLayerHRDParameters; + +typedef struct H265RawHRDParameters { + uint8_t nal_hrd_parameters_present_flag; + uint8_t vcl_hrd_parameters_present_flag; + + uint8_t sub_pic_hrd_params_present_flag; + uint8_t tick_divisor_minus2; + uint8_t du_cpb_removal_delay_increment_length_minus1; + uint8_t sub_pic_cpb_params_in_pic_timing_sei_flag; + uint8_t dpb_output_delay_du_length_minus1; + + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t cpb_size_du_scale; + + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t au_cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + + uint8_t fixed_pic_rate_general_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t fixed_pic_rate_within_cvs_flag[HEVC_MAX_SUB_LAYERS]; + uint16_t elemental_duration_in_tc_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t low_delay_hrd_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t cpb_cnt_minus1[HEVC_MAX_SUB_LAYERS]; + H265RawSubLayerHRDParameters nal_sub_layer_hrd_parameters[HEVC_MAX_SUB_LAYERS]; + H265RawSubLayerHRDParameters vcl_sub_layer_hrd_parameters[HEVC_MAX_SUB_LAYERS]; +} H265RawHRDParameters; + +typedef struct H265RawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + + uint8_t neutral_chroma_indication_flag; + uint8_t field_seq_flag; + uint8_t frame_field_info_present_flag; + + uint8_t default_display_window_flag; + uint16_t def_disp_win_left_offset; + uint16_t def_disp_win_right_offset; + uint16_t def_disp_win_top_offset; + uint16_t def_disp_win_bottom_offset; + + uint8_t vui_timing_info_present_flag; + uint32_t vui_num_units_in_tick; + uint32_t vui_time_scale; + uint8_t vui_poc_proportional_to_timing_flag; + uint32_t vui_num_ticks_poc_diff_one_minus1; + uint8_t vui_hrd_parameters_present_flag; + H265RawHRDParameters hrd_parameters; + + uint8_t bitstream_restriction_flag; + uint8_t tiles_fixed_structure_flag; + uint8_t motion_vectors_over_pic_boundaries_flag; + uint8_t restricted_ref_pic_lists_flag; + uint16_t min_spatial_segmentation_idc; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_min_cu_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; +} H265RawVUI; + +typedef struct H265RawPSExtensionData { + uint8_t *data; + size_t bit_length; +} H265RawPSExtensionData; + +typedef struct H265RawVPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t vps_video_parameter_set_id; + + uint8_t vps_base_layer_internal_flag; + uint8_t vps_base_layer_available_flag; + uint8_t vps_max_layers_minus1; + uint8_t vps_max_sub_layers_minus1; + uint8_t vps_temporal_id_nesting_flag; + + H265RawProfileTierLevel profile_tier_level; + + uint8_t vps_sub_layer_ordering_info_present_flag; + uint8_t vps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t vps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + uint32_t vps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; + + uint8_t vps_max_layer_id; + uint16_t vps_num_layer_sets_minus1; + uint8_t layer_id_included_flag[HEVC_MAX_LAYER_SETS][HEVC_MAX_LAYERS]; + + uint8_t vps_timing_info_present_flag; + uint32_t vps_num_units_in_tick; + uint32_t vps_time_scale; + uint8_t vps_poc_proportional_to_timing_flag; + uint32_t vps_num_ticks_poc_diff_one_minus1; + uint16_t vps_num_hrd_parameters; + uint16_t hrd_layer_set_idx[HEVC_MAX_LAYER_SETS]; + uint8_t cprms_present_flag[HEVC_MAX_LAYER_SETS]; + H265RawHRDParameters hrd_parameters[HEVC_MAX_LAYER_SETS]; + + uint8_t vps_extension_flag; + H265RawPSExtensionData extension_data; +} H265RawVPS; + +typedef struct H265RawSTRefPicSet { + uint8_t inter_ref_pic_set_prediction_flag; + + uint8_t delta_idx_minus1; + uint8_t delta_rps_sign; + uint16_t abs_delta_rps_minus1; + + uint8_t used_by_curr_pic_flag[HEVC_MAX_REFS]; + uint8_t use_delta_flag[HEVC_MAX_REFS]; + + uint8_t num_negative_pics; + uint8_t num_positive_pics; + uint16_t delta_poc_s0_minus1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s0_flag[HEVC_MAX_REFS]; + uint16_t delta_poc_s1_minus1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s1_flag[HEVC_MAX_REFS]; +} H265RawSTRefPicSet; + +typedef struct H265RawScalingList { + uint8_t scaling_list_pred_mode_flag[4][6]; + uint8_t scaling_list_pred_matrix_id_delta[4][6]; + int16_t scaling_list_dc_coef_minus8[4][6]; + int8_t scaling_list_delta_coeff[4][6][64]; +} H265RawScalingList; + +typedef struct H265RawSPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t sps_video_parameter_set_id; + + uint8_t sps_max_sub_layers_minus1; + uint8_t sps_temporal_id_nesting_flag; + + H265RawProfileTierLevel profile_tier_level; + + uint8_t sps_seq_parameter_set_id; + + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + + uint16_t pic_width_in_luma_samples; + uint16_t pic_height_in_luma_samples; + + uint8_t conformance_window_flag; + uint16_t conf_win_left_offset; + uint16_t conf_win_right_offset; + uint16_t conf_win_top_offset; + uint16_t conf_win_bottom_offset; + + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + + uint8_t log2_max_pic_order_cnt_lsb_minus4; + + uint8_t sps_sub_layer_ordering_info_present_flag; + uint8_t sps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t sps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + uint32_t sps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; + + uint8_t log2_min_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_luma_coding_block_size; + uint8_t log2_min_luma_transform_block_size_minus2; + uint8_t log2_diff_max_min_luma_transform_block_size; + uint8_t max_transform_hierarchy_depth_inter; + uint8_t max_transform_hierarchy_depth_intra; + + uint8_t scaling_list_enabled_flag; + uint8_t sps_scaling_list_data_present_flag; + H265RawScalingList scaling_list; + + uint8_t amp_enabled_flag; + uint8_t sample_adaptive_offset_enabled_flag; + + uint8_t pcm_enabled_flag; + uint8_t pcm_sample_bit_depth_luma_minus1; + uint8_t pcm_sample_bit_depth_chroma_minus1; + uint8_t log2_min_pcm_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_pcm_luma_coding_block_size; + uint8_t pcm_loop_filter_disabled_flag; + + uint8_t num_short_term_ref_pic_sets; + H265RawSTRefPicSet st_ref_pic_set[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; + + uint8_t long_term_ref_pics_present_flag; + uint8_t num_long_term_ref_pics_sps; + uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; + uint8_t used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; + + uint8_t sps_temporal_mvp_enabled_flag; + uint8_t strong_intra_smoothing_enabled_flag; + + uint8_t vui_parameters_present_flag; + H265RawVUI vui; + + uint8_t sps_extension_present_flag; + uint8_t sps_range_extension_flag; + uint8_t sps_multilayer_extension_flag; + uint8_t sps_3d_extension_flag; + uint8_t sps_scc_extension_flag; + uint8_t sps_extension_4bits; + + H265RawPSExtensionData extension_data; + + // Range extension. + uint8_t transform_skip_rotation_enabled_flag; + uint8_t transform_skip_context_enabled_flag; + uint8_t implicit_rdpcm_enabled_flag; + uint8_t explicit_rdpcm_enabled_flag; + uint8_t extended_precision_processing_flag; + uint8_t intra_smoothing_disabled_flag; + uint8_t high_precision_offsets_enabled_flag; + uint8_t persistent_rice_adaptation_enabled_flag; + uint8_t cabac_bypass_alignment_enabled_flag; + + // Screen content coding extension. + uint8_t sps_curr_pic_ref_enabled_flag; + uint8_t palette_mode_enabled_flag; + uint8_t palette_max_size; + uint8_t delta_palette_max_predictor_size; + uint8_t sps_palette_predictor_initializer_present_flag; + uint8_t sps_num_palette_predictor_initializer_minus1; + uint16_t sps_palette_predictor_initializers[3][128]; + + uint8_t motion_vector_resolution_control_idc; + uint8_t intra_boundary_filtering_disable_flag; +} H265RawSPS; + +typedef struct H265RawPPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t pps_pic_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + + uint8_t dependent_slice_segments_enabled_flag; + uint8_t output_flag_present_flag; + uint8_t num_extra_slice_header_bits; + uint8_t sign_data_hiding_enabled_flag; + uint8_t cabac_init_present_flag; + + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + + int8_t init_qp_minus26; + + uint8_t constrained_intra_pred_flag; + uint8_t transform_skip_enabled_flag; + uint8_t cu_qp_delta_enabled_flag; + uint8_t diff_cu_qp_delta_depth; + + int8_t pps_cb_qp_offset; + int8_t pps_cr_qp_offset; + uint8_t pps_slice_chroma_qp_offsets_present_flag; + + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_flag; + + uint8_t transquant_bypass_enabled_flag; + uint8_t tiles_enabled_flag; + uint8_t entropy_coding_sync_enabled_flag; + + uint8_t num_tile_columns_minus1; + uint8_t num_tile_rows_minus1; + uint8_t uniform_spacing_flag; + uint16_t column_width_minus1[HEVC_MAX_TILE_COLUMNS]; + uint16_t row_height_minus1[HEVC_MAX_TILE_ROWS]; + uint8_t loop_filter_across_tiles_enabled_flag; + + uint8_t pps_loop_filter_across_slices_enabled_flag; + uint8_t deblocking_filter_control_present_flag; + uint8_t deblocking_filter_override_enabled_flag; + uint8_t pps_deblocking_filter_disabled_flag; + int8_t pps_beta_offset_div2; + int8_t pps_tc_offset_div2; + + uint8_t pps_scaling_list_data_present_flag; + H265RawScalingList scaling_list; + + uint8_t lists_modification_present_flag; + uint8_t log2_parallel_merge_level_minus2; + + uint8_t slice_segment_header_extension_present_flag; + + uint8_t pps_extension_present_flag; + uint8_t pps_range_extension_flag; + uint8_t pps_multilayer_extension_flag; + uint8_t pps_3d_extension_flag; + uint8_t pps_scc_extension_flag; + uint8_t pps_extension_4bits; + + H265RawPSExtensionData extension_data; + + // Range extension. + uint8_t log2_max_transform_skip_block_size_minus2; + uint8_t cross_component_prediction_enabled_flag; + uint8_t chroma_qp_offset_list_enabled_flag; + uint8_t diff_cu_chroma_qp_offset_depth; + uint8_t chroma_qp_offset_list_len_minus1; + int8_t cb_qp_offset_list[6]; + int8_t cr_qp_offset_list[6]; + uint8_t log2_sao_offset_scale_luma; + uint8_t log2_sao_offset_scale_chroma; + + // Screen content coding extension. + uint8_t pps_curr_pic_ref_enabled_flag; + uint8_t residual_adaptive_colour_transform_enabled_flag; + uint8_t pps_slice_act_qp_offsets_present_flag; + int8_t pps_act_y_qp_offset_plus5; + int8_t pps_act_cb_qp_offset_plus5; + int8_t pps_act_cr_qp_offset_plus3; + + uint8_t pps_palette_predictor_initializer_present_flag; + uint8_t pps_num_palette_predictor_initializer; + uint8_t monochrome_palette_flag; + uint8_t luma_bit_depth_entry_minus8; + uint8_t chroma_bit_depth_entry_minus8; + uint16_t pps_palette_predictor_initializers[3][128]; +} H265RawPPS; + +typedef struct H265RawAUD { + H265RawNALUnitHeader nal_unit_header; + + uint8_t pic_type; +} H265RawAUD; + +typedef struct H265RawSliceHeader { + H265RawNALUnitHeader nal_unit_header; + + uint8_t first_slice_segment_in_pic_flag; + uint8_t no_output_of_prior_pics_flag; + uint8_t slice_pic_parameter_set_id; + + uint8_t dependent_slice_segment_flag; + uint16_t slice_segment_address; + + uint8_t slice_reserved_flag[8]; + uint8_t slice_type; + + uint8_t pic_output_flag; + uint8_t colour_plane_id; + + uint16_t slice_pic_order_cnt_lsb; + + uint8_t short_term_ref_pic_set_sps_flag; + H265RawSTRefPicSet short_term_ref_pic_set; + uint8_t short_term_ref_pic_set_idx; + + uint8_t num_long_term_sps; + uint8_t num_long_term_pics; + uint8_t lt_idx_sps[HEVC_MAX_REFS]; + uint8_t poc_lsb_lt[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_lt_flag[HEVC_MAX_REFS]; + uint8_t delta_poc_msb_present_flag[HEVC_MAX_REFS]; + uint32_t delta_poc_msb_cycle_lt[HEVC_MAX_REFS]; + + uint8_t slice_temporal_mvp_enabled_flag; + + uint8_t slice_sao_luma_flag; + uint8_t slice_sao_chroma_flag; + + uint8_t num_ref_idx_active_override_flag; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + + uint8_t ref_pic_list_modification_flag_l0; + uint8_t list_entry_l0[HEVC_MAX_REFS]; + uint8_t ref_pic_list_modification_flag_l1; + uint8_t list_entry_l1[HEVC_MAX_REFS]; + + uint8_t mvd_l1_zero_flag; + uint8_t cabac_init_flag; + uint8_t collocated_from_l0_flag; + uint8_t collocated_ref_idx; + + uint8_t luma_log2_weight_denom; + int8_t delta_chroma_log2_weight_denom; + uint8_t luma_weight_l0_flag[HEVC_MAX_REFS]; + uint8_t chroma_weight_l0_flag[HEVC_MAX_REFS]; + int8_t delta_luma_weight_l0[HEVC_MAX_REFS]; + int16_t luma_offset_l0[HEVC_MAX_REFS]; + int8_t delta_chroma_weight_l0[HEVC_MAX_REFS][2]; + int16_t chroma_offset_l0[HEVC_MAX_REFS][2]; + uint8_t luma_weight_l1_flag[HEVC_MAX_REFS]; + uint8_t chroma_weight_l1_flag[HEVC_MAX_REFS]; + int8_t delta_luma_weight_l1[HEVC_MAX_REFS]; + int16_t luma_offset_l1[HEVC_MAX_REFS]; + int8_t delta_chroma_weight_l1[HEVC_MAX_REFS][2]; + int16_t chroma_offset_l1[HEVC_MAX_REFS][2]; + + uint8_t five_minus_max_num_merge_cand; + uint8_t use_integer_mv_flag; + + int8_t slice_qp_delta; + int8_t slice_cb_qp_offset; + int8_t slice_cr_qp_offset; + int8_t slice_act_y_qp_offset; + int8_t slice_act_cb_qp_offset; + int8_t slice_act_cr_qp_offset; + uint8_t cu_chroma_qp_offset_enabled_flag; + + uint8_t deblocking_filter_override_flag; + uint8_t slice_deblocking_filter_disabled_flag; + int8_t slice_beta_offset_div2; + int8_t slice_tc_offset_div2; + uint8_t slice_loop_filter_across_slices_enabled_flag; + + uint16_t num_entry_point_offsets; + uint8_t offset_len_minus1; + uint32_t entry_point_offset_minus1[HEVC_MAX_ENTRY_POINT_OFFSETS]; + + uint16_t slice_segment_header_extension_length; + uint8_t slice_segment_header_extension_data_byte[256]; +} H265RawSliceHeader; + + +typedef struct H265RawSlice { + H265RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; +} H265RawSlice; + + +typedef struct CodedBitstreamH265Context { + // Reader/writer context in common with the H.264 implementation. + CodedBitstreamH2645Context common; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + H265RawVPS *vps[HEVC_MAX_VPS_COUNT]; + H265RawSPS *sps[HEVC_MAX_SPS_COUNT]; + H265RawPPS *pps[HEVC_MAX_PPS_COUNT]; + + // The currently active parameter sets. These are updated when any + // NAL unit refers to the relevant parameter set. These pointers + // must also be present in the arrays above. + const H265RawVPS *active_vps; + const H265RawSPS *active_sps; + const H265RawPPS *active_pps; +} CodedBitstreamH265Context; + + +#endif /* AVCODEC_CBS_H265_H */ diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c new file mode 100644 index 000000000..dae7f2dd4 --- /dev/null +++ b/libavcodec/cbs_h265_syntax_template.c @@ -0,0 +1,1503 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int one = 1, zero = 0; + xu(1, rbsp_stop_one_bit, one, 1, 1); + while (byte_alignment(rw) != 0) + xu(1, rbsp_alignment_zero_bit, zero, 0, 0); + + return 0; +} + +static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawNALUnitHeader *current, + int expected_nal_unit_type) +{ + int err; + + u(1, forbidden_zero_bit, 0, 0); + + if (expected_nal_unit_type >= 0) + u(6, nal_unit_type, expected_nal_unit_type, + expected_nal_unit_type); + else + u(6, nal_unit_type, 0, 63); + + u(6, nuh_layer_id, 0, 62); + u(3, nuh_temporal_id_plus1, 1, 7); + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int one = 1, zero = 0; + xu(1, alignment_bit_equal_to_one, one, 1, 1); + while (byte_alignment(rw) != 0) + xu(1, alignment_bit_equal_to_zero, zero, 0, 0); + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPSExtensionData *current) +{ + int err; + size_t k; +#ifdef READ + GetBitContext start; + uint8_t bit; + start = *rw; + for (k = 0; cbs_h2645_read_more_rbsp_data(rw); k++) + skip_bits(rw, 1); + current->bit_length = k; + if (k > 0) { + *rw = start; + allocate(current->data, (current->bit_length + 7) / 8); + for (k = 0; k < current->bit_length; k++) { + xu(1, extension_data, bit, 0, 1); + current->data[k / 8] |= bit << (7 - k % 8); + } + } +#else + for (k = 0; k < current->bit_length; k++) + xu(1, extension_data, current->data[k / 8] >> (7 - k % 8), 0, 1); +#endif + return 0; +} + +static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawProfileTierLevel *current, + int profile_present_flag, + int max_num_sub_layers_minus1) +{ + av_unused unsigned int zero = 0; + int err, i, j; + + if (profile_present_flag) { + u(2, general_profile_space, 0, 0); + flag(general_tier_flag); + u(5, general_profile_idc, 0, 31); + + for (j = 0; j < 32; j++) + flag(general_profile_compatibility_flag[j]); + + flag(general_progressive_source_flag); + flag(general_interlaced_source_flag); + flag(general_non_packed_constraint_flag); + flag(general_frame_only_constraint_flag); + +#define profile_compatible(x) (current->general_profile_idc == (x) || \ + current->general_profile_compatibility_flag[x]) + if (profile_compatible(4) || profile_compatible(5) || + profile_compatible(6) || profile_compatible(7) || + profile_compatible(8) || profile_compatible(9) || + profile_compatible(10)) { + flag(general_max_12bit_constraint_flag); + flag(general_max_10bit_constraint_flag); + flag(general_max_8bit_constraint_flag); + flag(general_max_422chroma_constraint_flag); + flag(general_max_420chroma_constraint_flag); + flag(general_max_monochrome_constraint_flag); + flag(general_intra_constraint_flag); + flag(general_one_picture_only_constraint_flag); + flag(general_lower_bit_rate_constraint_flag); + + if (profile_compatible(5) || profile_compatible(9) || + profile_compatible(10)) { + flag(general_max_14bit_constraint_flag); + xu(24, general_reserved_zero_33bits, zero, 0, 0); + xu(9, general_reserved_zero_33bits, zero, 0, 0); + } else { + xu(24, general_reserved_zero_34bits, zero, 0, 0); + xu(10, general_reserved_zero_34bits, zero, 0, 0); + } + } else { + xu(24, general_reserved_zero_43bits, zero, 0, 0); + xu(19, general_reserved_zero_43bits, zero, 0, 0); + } + + if (profile_compatible(1) || profile_compatible(2) || + profile_compatible(3) || profile_compatible(4) || + profile_compatible(5) || profile_compatible(9)) { + flag(general_inbld_flag); + } else { + xu(1, general_reserved_zero_bit, zero, 0, 0); + } +#undef profile_compatible + } + + u(8, general_level_idc, 0, 255); + + for (i = 0; i < max_num_sub_layers_minus1; i++) { + flag(sub_layer_profile_present_flag[i]); + flag(sub_layer_level_present_flag[i]); + } + + if (max_num_sub_layers_minus1 > 0) { + for (i = max_num_sub_layers_minus1; i < 8; i++) { + av_unused int zero = 0; + xu(2, reserved_zero_2bits, zero, 0, 0); + } + } + + for (i = 0; i < max_num_sub_layers_minus1; i++) { + if (current->sub_layer_profile_present_flag[i]) + return AVERROR_PATCHWELCOME; + if (current->sub_layer_level_present_flag[i]) + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int FUNC(sub_layer_hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawHRDParameters *hrd, + int nal, int sub_layer_id) +{ + H265RawSubLayerHRDParameters *current; + int err, i; + + if (nal) + current = &hrd->nal_sub_layer_hrd_parameters[sub_layer_id]; + else + current = &hrd->vcl_sub_layer_hrd_parameters[sub_layer_id]; + + for (i = 0; i <= hrd->cpb_cnt_minus1[sub_layer_id]; i++) { + ue(bit_rate_value_minus1[i], 0, UINT32_MAX - 1); + ue(cpb_size_value_minus1[i], 0, UINT32_MAX - 1); + if (hrd->sub_pic_hrd_params_present_flag) { + ue(cpb_size_du_value_minus1[i], 0, UINT32_MAX - 1); + ue(bit_rate_du_value_minus1[i], 0, UINT32_MAX - 1); + } + flag(cbr_flag[i]); + } + + return 0; +} + +static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawHRDParameters *current, int common_inf_present_flag, + int max_num_sub_layers_minus1) +{ + int err, i; + + if (common_inf_present_flag) { + flag(nal_hrd_parameters_present_flag); + flag(vcl_hrd_parameters_present_flag); + + if (current->nal_hrd_parameters_present_flag || + current->vcl_hrd_parameters_present_flag) { + flag(sub_pic_hrd_params_present_flag); + if (current->sub_pic_hrd_params_present_flag) { + u(8, tick_divisor_minus2, 0, 255); + u(5, du_cpb_removal_delay_increment_length_minus1, 0, 31); + flag(sub_pic_cpb_params_in_pic_timing_sei_flag); + u(5, dpb_output_delay_du_length_minus1, 0, 31); + } + + u(4, bit_rate_scale, 0, 15); + u(4, cpb_size_scale, 0, 15); + if (current->sub_pic_hrd_params_present_flag) + u(4, cpb_size_du_scale, 0, 15); + + u(5, initial_cpb_removal_delay_length_minus1, 0, 31); + u(5, au_cpb_removal_delay_length_minus1, 0, 31); + u(5, dpb_output_delay_length_minus1, 0, 31); + } else { + infer(sub_pic_hrd_params_present_flag, 0); + + infer(initial_cpb_removal_delay_length_minus1, 23); + infer(au_cpb_removal_delay_length_minus1, 23); + infer(dpb_output_delay_length_minus1, 23); + } + } + + for (i = 0; i <= max_num_sub_layers_minus1; i++) { + flag(fixed_pic_rate_general_flag[i]); + + if (!current->fixed_pic_rate_general_flag[i]) + flag(fixed_pic_rate_within_cvs_flag[i]); + else + infer(fixed_pic_rate_within_cvs_flag[i], 1); + + if (current->fixed_pic_rate_within_cvs_flag[i]) { + ue(elemental_duration_in_tc_minus1[i], 0, 2047); + infer(low_delay_hrd_flag[i], 0); + } else + flag(low_delay_hrd_flag[i]); + + if (!current->low_delay_hrd_flag[i]) + ue(cpb_cnt_minus1[i], 0, 31); + else + infer(cpb_cnt_minus1[i], 0); + + if (current->nal_hrd_parameters_present_flag) + CHECK(FUNC(sub_layer_hrd_parameters)(ctx, rw, current, 0, i)); + if (current->vcl_hrd_parameters_present_flag) + CHECK(FUNC(sub_layer_hrd_parameters)(ctx, rw, current, 1, i)); + } + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawVUI *current, const H265RawSPS *sps) +{ + int err; + + flag(aspect_ratio_info_present_flag); + if (current->aspect_ratio_info_present_flag) { + u(8, aspect_ratio_idc, 0, 255); + if (current->aspect_ratio_idc == 255) { + u(16, sar_width, 0, 65535); + u(16, sar_height, 0, 65535); + } + } else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if (current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + + flag(video_signal_type_present_flag); + if (current->video_signal_type_present_flag) { + u(3, video_format, 0, 7); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if (current->colour_description_present_flag) { + u(8, colour_primaries, 0, 255); + u(8, transfer_characteristics, 0, 255); + u(8, matrix_coefficients, 0, 255); + } else { + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + } else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + flag(chroma_loc_info_present_flag); + if (current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + flag(neutral_chroma_indication_flag); + flag(field_seq_flag); + flag(frame_field_info_present_flag); + + flag(default_display_window_flag); + if (current->default_display_window_flag) { + ue(def_disp_win_left_offset, 0, 16384); + ue(def_disp_win_right_offset, 0, 16384); + ue(def_disp_win_top_offset, 0, 16384); + ue(def_disp_win_bottom_offset, 0, 16384); + } + + flag(vui_timing_info_present_flag); + if (current->vui_timing_info_present_flag) { + u(32, vui_num_units_in_tick, 1, UINT32_MAX); + u(32, vui_time_scale, 1, UINT32_MAX); + flag(vui_poc_proportional_to_timing_flag); + if (current->vui_poc_proportional_to_timing_flag) + ue(vui_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); + + flag(vui_hrd_parameters_present_flag); + if (current->vui_hrd_parameters_present_flag) { + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->hrd_parameters, + 1, sps->sps_max_sub_layers_minus1)); + } + } + + flag(bitstream_restriction_flag); + if (current->bitstream_restriction_flag) { + flag(tiles_fixed_structure_flag); + flag(motion_vectors_over_pic_boundaries_flag); + flag(restricted_ref_pic_lists_flag); + ue(min_spatial_segmentation_idc, 0, 4095); + ue(max_bytes_per_pic_denom, 0, 16); + ue(max_bits_per_min_cu_denom, 0, 16); + ue(log2_max_mv_length_horizontal, 0, 16); + ue(log2_max_mv_length_vertical, 0, 16); + } else { + infer(tiles_fixed_structure_flag, 0); + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(min_spatial_segmentation_idc, 0); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_min_cu_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + } + + return 0; +} + +static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawVPS *current) +{ + int err, i, j; + + HEADER("Video Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_VPS)); + + u(4, vps_video_parameter_set_id, 0, 15); + + flag(vps_base_layer_internal_flag); + flag(vps_base_layer_available_flag); + u(6, vps_max_layers_minus1, 0, HEVC_MAX_LAYERS - 1); + u(3, vps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); + flag(vps_temporal_id_nesting_flag); + + if (current->vps_max_sub_layers_minus1 == 0 && + current->vps_temporal_id_nesting_flag != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "vps_temporal_id_nesting_flag must be 1 if " + "vps_max_sub_layers_minus1 is 0.\n"); + return AVERROR_INVALIDDATA; + } + + { + av_unused uint16_t ffff = 0xffff; + xu(16, vps_reserved_0xffff_16bits, ffff, 0xffff, 0xffff); + } + + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->vps_max_sub_layers_minus1)); + + flag(vps_sub_layer_ordering_info_present_flag); + for (i = (current->vps_sub_layer_ordering_info_present_flag ? + 0 : current->vps_max_sub_layers_minus1); + i <= current->vps_max_sub_layers_minus1; i++) { + ue(vps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_SIZE - 1); + ue(vps_max_num_reorder_pics[i], 0, current->vps_max_dec_pic_buffering_minus1[i]); + ue(vps_max_latency_increase_plus1[i], 0, UINT32_MAX - 1); + } + if (!current->vps_sub_layer_ordering_info_present_flag) { + for (i = 0; i < current->vps_max_sub_layers_minus1; i++) { + infer(vps_max_dec_pic_buffering_minus1[i], + current->vps_max_dec_pic_buffering_minus1[current->vps_max_sub_layers_minus1]); + infer(vps_max_num_reorder_pics[i], + current->vps_max_num_reorder_pics[current->vps_max_sub_layers_minus1]); + infer(vps_max_latency_increase_plus1[i], + current->vps_max_latency_increase_plus1[current->vps_max_sub_layers_minus1]); + } + } + + u(6, vps_max_layer_id, 0, HEVC_MAX_LAYERS - 1); + ue(vps_num_layer_sets_minus1, 0, HEVC_MAX_LAYER_SETS - 1); + for (i = 1; i <= current->vps_num_layer_sets_minus1; i++) { + for (j = 0; j <= current->vps_max_layer_id; j++) + flag(layer_id_included_flag[i][j]); + } + for (j = 0; j <= current->vps_max_layer_id; j++) + infer(layer_id_included_flag[0][j], j == 0); + + flag(vps_timing_info_present_flag); + if (current->vps_timing_info_present_flag) { + u(32, vps_num_units_in_tick, 1, UINT32_MAX); + u(32, vps_time_scale, 1, UINT32_MAX); + flag(vps_poc_proportional_to_timing_flag); + if (current->vps_poc_proportional_to_timing_flag) + ue(vps_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); + ue(vps_num_hrd_parameters, 0, current->vps_num_layer_sets_minus1 + 1); + for (i = 0; i < current->vps_num_hrd_parameters; i++) { + ue(hrd_layer_set_idx[i], + current->vps_base_layer_internal_flag ? 0 : 1, + current->vps_num_layer_sets_minus1); + if (i > 0) + flag(cprms_present_flag[i]); + else + infer(cprms_present_flag[0], 1); + + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->hrd_parameters[i], + current->cprms_present_flag[i], + current->vps_max_sub_layers_minus1)); + } + } + + flag(vps_extension_flag); + if (current->vps_extension_flag) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(st_ref_pic_set)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSTRefPicSet *current, int st_rps_idx, + const H265RawSPS *sps) +{ + int err, i, j; + + if (st_rps_idx != 0) + flag(inter_ref_pic_set_prediction_flag); + else + infer(inter_ref_pic_set_prediction_flag, 0); + + if (current->inter_ref_pic_set_prediction_flag) { + unsigned int ref_rps_idx, num_delta_pocs; + const H265RawSTRefPicSet *ref; + int delta_rps, d_poc; + int ref_delta_poc_s0[HEVC_MAX_REFS], ref_delta_poc_s1[HEVC_MAX_REFS]; + int delta_poc_s0[HEVC_MAX_REFS], delta_poc_s1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s0[HEVC_MAX_REFS], + used_by_curr_pic_s1[HEVC_MAX_REFS]; + + if (st_rps_idx == sps->num_short_term_ref_pic_sets) + ue(delta_idx_minus1, 0, st_rps_idx - 1); + else + infer(delta_idx_minus1, 0); + + ref_rps_idx = st_rps_idx - (current->delta_idx_minus1 + 1); + ref = &sps->st_ref_pic_set[ref_rps_idx]; + num_delta_pocs = ref->num_negative_pics + ref->num_positive_pics; + + flag(delta_rps_sign); + ue(abs_delta_rps_minus1, 0, INT16_MAX); + delta_rps = (1 - 2 * current->delta_rps_sign) * + (current->abs_delta_rps_minus1 + 1); + + for (j = 0; j <= num_delta_pocs; j++) { + flag(used_by_curr_pic_flag[j]); + if (!current->used_by_curr_pic_flag[j]) + flag(use_delta_flag[j]); + else + infer(use_delta_flag[j], 1); + } + + // Since the stored form of an RPS here is actually the delta-step + // form used when inter_ref_pic_set_prediction_flag is not set, we + // need to reconstruct that here in order to be able to refer to + // the RPS later (which is required for parsing, because we don't + // even know what syntax elements appear without it). Therefore, + // this code takes the delta-step form of the reference set, turns + // it into the delta-array form, applies the prediction process of + // 7.4.8, converts the result back to the delta-step form, and + // stores that as the current set for future use. Note that the + // inferences here mean that writers using prediction will need + // to fill in the delta-step values correctly as well - since the + // whole RPS prediction process is somewhat overly sophisticated, + // this hopefully forms a useful check for them to ensure their + // predicted form actually matches what was intended rather than + // an onerous additional requirement. + + d_poc = 0; + for (i = 0; i < ref->num_negative_pics; i++) { + d_poc -= ref->delta_poc_s0_minus1[i] + 1; + ref_delta_poc_s0[i] = d_poc; + } + d_poc = 0; + for (i = 0; i < ref->num_positive_pics; i++) { + d_poc += ref->delta_poc_s1_minus1[i] + 1; + ref_delta_poc_s1[i] = d_poc; + } + + i = 0; + for (j = ref->num_positive_pics - 1; j >= 0; j--) { + d_poc = ref_delta_poc_s1[j] + delta_rps; + if (d_poc < 0 && current->use_delta_flag[ref->num_negative_pics + j]) { + delta_poc_s0[i] = d_poc; + used_by_curr_pic_s0[i++] = + current->used_by_curr_pic_flag[ref->num_negative_pics + j]; + } + } + if (delta_rps < 0 && current->use_delta_flag[num_delta_pocs]) { + delta_poc_s0[i] = delta_rps; + used_by_curr_pic_s0[i++] = + current->used_by_curr_pic_flag[num_delta_pocs]; + } + for (j = 0; j < ref->num_negative_pics; j++) { + d_poc = ref_delta_poc_s0[j] + delta_rps; + if (d_poc < 0 && current->use_delta_flag[j]) { + delta_poc_s0[i] = d_poc; + used_by_curr_pic_s0[i++] = current->used_by_curr_pic_flag[j]; + } + } + + infer(num_negative_pics, i); + for (i = 0; i < current->num_negative_pics; i++) { + infer(delta_poc_s0_minus1[i], + -(delta_poc_s0[i] - (i == 0 ? 0 : delta_poc_s0[i - 1])) - 1); + infer(used_by_curr_pic_s0_flag[i], used_by_curr_pic_s0[i]); + } + + i = 0; + for (j = ref->num_negative_pics - 1; j >= 0; j--) { + d_poc = ref_delta_poc_s0[j] + delta_rps; + if (d_poc > 0 && current->use_delta_flag[j]) { + delta_poc_s1[i] = d_poc; + used_by_curr_pic_s1[i++] = current->used_by_curr_pic_flag[j]; + } + } + if (delta_rps > 0 && current->use_delta_flag[num_delta_pocs]) { + delta_poc_s1[i] = delta_rps; + used_by_curr_pic_s1[i++] = + current->used_by_curr_pic_flag[num_delta_pocs]; + } + for (j = 0; j < ref->num_positive_pics; j++) { + d_poc = ref_delta_poc_s1[j] + delta_rps; + if (d_poc > 0 && current->use_delta_flag[ref->num_negative_pics + j]) { + delta_poc_s1[i] = d_poc; + used_by_curr_pic_s1[i++] = + current->used_by_curr_pic_flag[ref->num_negative_pics + j]; + } + } + + infer(num_positive_pics, i); + for (i = 0; i < current->num_positive_pics; i++) { + infer(delta_poc_s1_minus1[i], + delta_poc_s1[i] - (i == 0 ? 0 : delta_poc_s1[i - 1]) - 1); + infer(used_by_curr_pic_s1_flag[i], used_by_curr_pic_s1[i]); + } + + } else { + ue(num_negative_pics, 0, 15); + ue(num_positive_pics, 0, 15 - current->num_negative_pics); + + for (i = 0; i < current->num_negative_pics; i++) { + ue(delta_poc_s0_minus1[i], 0, INT16_MAX); + flag(used_by_curr_pic_s0_flag[i]); + } + + for (i = 0; i < current->num_positive_pics; i++) { + ue(delta_poc_s1_minus1[i], 0, INT16_MAX); + flag(used_by_curr_pic_s1_flag[i]); + } + } + + return 0; +} + +static int FUNC(scaling_list_data)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawScalingList *current) +{ + int sizeId, matrixId; + int err, n, i; + + for (sizeId = 0; sizeId < 4; sizeId++) { + for (matrixId = 0; matrixId < 6; matrixId += (sizeId == 3 ? 3 : 1)) { + flag(scaling_list_pred_mode_flag[sizeId][matrixId]); + if (!current->scaling_list_pred_mode_flag[sizeId][matrixId]) { + ue(scaling_list_pred_matrix_id_delta[sizeId][matrixId], + 0, sizeId == 3 ? matrixId / 3 : matrixId); + } else { + n = FFMIN(64, 1 << (4 + (sizeId << 1))); + if (sizeId > 1) + se(scaling_list_dc_coef_minus8[sizeId - 2][matrixId], -7, +247); + for (i = 0; i < n; i++) { + xse(scaling_list_delta_coeff, + current->scaling_list_delta_coeff[sizeId][matrixId][i], + -128, +127); + } + } + } + } + + return 0; +} + +static int FUNC(sps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + int err; + + flag(transform_skip_rotation_enabled_flag); + flag(transform_skip_context_enabled_flag); + flag(implicit_rdpcm_enabled_flag); + flag(explicit_rdpcm_enabled_flag); + flag(extended_precision_processing_flag); + flag(intra_smoothing_disabled_flag); + flag(high_precision_offsets_enabled_flag); + flag(persistent_rice_adaptation_enabled_flag); + flag(cabac_bypass_alignment_enabled_flag); + + return 0; +} + +static int FUNC(sps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + int err, comp, i; + + flag(sps_curr_pic_ref_enabled_flag); + + flag(palette_mode_enabled_flag); + if (current->palette_mode_enabled_flag) { + ue(palette_max_size, 0, 64); + ue(delta_palette_max_predictor_size, 0, 128); + + flag(sps_palette_predictor_initializer_present_flag); + if (current->sps_palette_predictor_initializer_present_flag) { + ue(sps_num_palette_predictor_initializer_minus1, 0, 128); + for (comp = 0; comp < (current->chroma_format_idc ? 3 : 1); comp++) { + int bit_depth = comp == 0 ? current->bit_depth_luma_minus8 + 8 + : current->bit_depth_chroma_minus8 + 8; + for (i = 0; i <= current->sps_num_palette_predictor_initializer_minus1; i++) + u(bit_depth, sps_palette_predictor_initializers[comp][i], + 0, (1 << bit_depth) - 1); + } + } + } + + u(2, motion_vector_resolution_control_idc, 0, 2); + flag(intra_boundary_filtering_disable_flag); + + return 0; +} + +static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawVPS *vps; + int err, i; + unsigned int min_cb_log2_size_y, ctb_log2_size_y, + min_cb_size_y, min_tb_log2_size_y; + + HEADER("Sequence Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_SPS)); + + u(4, sps_video_parameter_set_id, 0, 15); + h265->active_vps = vps = h265->vps[current->sps_video_parameter_set_id]; + + u(3, sps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); + flag(sps_temporal_id_nesting_flag); + if (vps) { + if (vps->vps_max_sub_layers_minus1 > current->sps_max_sub_layers_minus1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_max_sub_layers_minus1 (%d) must be less than or equal to " + "vps_max_sub_layers_minus1 (%d).\n", + vps->vps_max_sub_layers_minus1, + current->sps_max_sub_layers_minus1); + return AVERROR_INVALIDDATA; + } + if (vps->vps_temporal_id_nesting_flag && + !current->sps_temporal_id_nesting_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_temporal_id_nesting_flag must be 1 if " + "vps_temporal_id_nesting_flag is 1.\n"); + return AVERROR_INVALIDDATA; + } + } + + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->sps_max_sub_layers_minus1)); + + ue(sps_seq_parameter_set_id, 0, 15); + + ue(chroma_format_idc, 0, 3); + if (current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); + + ue(pic_width_in_luma_samples, 1, HEVC_MAX_WIDTH); + ue(pic_height_in_luma_samples, 1, HEVC_MAX_HEIGHT); + + flag(conformance_window_flag); + if (current->conformance_window_flag) { + ue(conf_win_left_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_right_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_top_offset, 0, current->pic_height_in_luma_samples); + ue(conf_win_bottom_offset, 0, current->pic_height_in_luma_samples); + } else { + infer(conf_win_left_offset, 0); + infer(conf_win_right_offset, 0); + infer(conf_win_top_offset, 0); + infer(conf_win_bottom_offset, 0); + } + + ue(bit_depth_luma_minus8, 0, 8); + ue(bit_depth_chroma_minus8, 0, 8); + + ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); + + flag(sps_sub_layer_ordering_info_present_flag); + for (i = (current->sps_sub_layer_ordering_info_present_flag ? + 0 : current->sps_max_sub_layers_minus1); + i <= current->sps_max_sub_layers_minus1; i++) { + ue(sps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_SIZE - 1); + ue(sps_max_num_reorder_pics[i], 0, current->sps_max_dec_pic_buffering_minus1[i]); + ue(sps_max_latency_increase_plus1[i], 0, UINT32_MAX - 1); + } + if (!current->sps_sub_layer_ordering_info_present_flag) { + for (i = 0; i < current->sps_max_sub_layers_minus1; i++) { + infer(sps_max_dec_pic_buffering_minus1[i], + current->sps_max_dec_pic_buffering_minus1[current->sps_max_sub_layers_minus1]); + infer(sps_max_num_reorder_pics[i], + current->sps_max_num_reorder_pics[current->sps_max_sub_layers_minus1]); + infer(sps_max_latency_increase_plus1[i], + current->sps_max_latency_increase_plus1[current->sps_max_sub_layers_minus1]); + } + } + + ue(log2_min_luma_coding_block_size_minus3, 0, 3); + min_cb_log2_size_y = current->log2_min_luma_coding_block_size_minus3 + 3; + + ue(log2_diff_max_min_luma_coding_block_size, 0, 3); + ctb_log2_size_y = min_cb_log2_size_y + + current->log2_diff_max_min_luma_coding_block_size; + + min_cb_size_y = 1 << min_cb_log2_size_y; + if (current->pic_width_in_luma_samples % min_cb_size_y || + current->pic_height_in_luma_samples % min_cb_size_y) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid dimensions: %ux%u not divisible " + "by MinCbSizeY = %u.\n", current->pic_width_in_luma_samples, + current->pic_height_in_luma_samples, min_cb_size_y); + return AVERROR_INVALIDDATA; + } + + ue(log2_min_luma_transform_block_size_minus2, 0, min_cb_log2_size_y - 3); + min_tb_log2_size_y = current->log2_min_luma_transform_block_size_minus2 + 2; + + ue(log2_diff_max_min_luma_transform_block_size, + 0, FFMIN(ctb_log2_size_y, 5) - min_tb_log2_size_y); + + ue(max_transform_hierarchy_depth_inter, + 0, ctb_log2_size_y - min_tb_log2_size_y); + ue(max_transform_hierarchy_depth_intra, + 0, ctb_log2_size_y - min_tb_log2_size_y); + + flag(scaling_list_enabled_flag); + if (current->scaling_list_enabled_flag) { + flag(sps_scaling_list_data_present_flag); + if (current->sps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + } else { + infer(sps_scaling_list_data_present_flag, 0); + } + + flag(amp_enabled_flag); + flag(sample_adaptive_offset_enabled_flag); + + flag(pcm_enabled_flag); + if (current->pcm_enabled_flag) { + u(4, pcm_sample_bit_depth_luma_minus1, + 0, current->bit_depth_luma_minus8 + 8 - 1); + u(4, pcm_sample_bit_depth_chroma_minus1, + 0, current->bit_depth_chroma_minus8 + 8 - 1); + + ue(log2_min_pcm_luma_coding_block_size_minus3, + FFMIN(min_cb_log2_size_y, 5) - 3, FFMIN(ctb_log2_size_y, 5) - 3); + ue(log2_diff_max_min_pcm_luma_coding_block_size, + 0, FFMIN(ctb_log2_size_y, 5) - (current->log2_min_pcm_luma_coding_block_size_minus3 + 3)); + + flag(pcm_loop_filter_disabled_flag); + } + + ue(num_short_term_ref_pic_sets, 0, HEVC_MAX_SHORT_TERM_REF_PIC_SETS); + for (i = 0; i < current->num_short_term_ref_pic_sets; i++) + CHECK(FUNC(st_ref_pic_set)(ctx, rw, ¤t->st_ref_pic_set[i], i, current)); + + flag(long_term_ref_pics_present_flag); + if (current->long_term_ref_pics_present_flag) { + ue(num_long_term_ref_pics_sps, 0, HEVC_MAX_LONG_TERM_REF_PICS); + for (i = 0; i < current->num_long_term_ref_pics_sps; i++) { + u(current->log2_max_pic_order_cnt_lsb_minus4 + 4, + lt_ref_pic_poc_lsb_sps[i], + 0, (1 << (current->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1); + flag(used_by_curr_pic_lt_sps_flag[i]); + } + } + + flag(sps_temporal_mvp_enabled_flag); + flag(strong_intra_smoothing_enabled_flag); + + flag(vui_parameters_present_flag); + if (current->vui_parameters_present_flag) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + + flag(sps_extension_present_flag); + if (current->sps_extension_present_flag) { + flag(sps_range_extension_flag); + flag(sps_multilayer_extension_flag); + flag(sps_3d_extension_flag); + flag(sps_scc_extension_flag); + u(4, sps_extension_4bits, 0, (1 << 4) - 1); + } + + if (current->sps_range_extension_flag) + CHECK(FUNC(sps_range_extension)(ctx, rw, current)); + if (current->sps_multilayer_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->sps_3d_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->sps_scc_extension_flag) + CHECK(FUNC(sps_scc_extension)(ctx, rw, current)); + if (current->sps_extension_4bits) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(pps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, i; + + if (current->transform_skip_enabled_flag) + ue(log2_max_transform_skip_block_size_minus2, 0, 3); + flag(cross_component_prediction_enabled_flag); + + flag(chroma_qp_offset_list_enabled_flag); + if (current->chroma_qp_offset_list_enabled_flag) { + ue(diff_cu_chroma_qp_offset_depth, + 0, sps->log2_diff_max_min_luma_coding_block_size); + ue(chroma_qp_offset_list_len_minus1, 0, 5); + for (i = 0; i <= current->chroma_qp_offset_list_len_minus1; i++) { + se(cb_qp_offset_list[i], -12, +12); + se(cr_qp_offset_list[i], -12, +12); + } + } + + ue(log2_sao_offset_scale_luma, 0, FFMAX(0, sps->bit_depth_luma_minus8 - 2)); + ue(log2_sao_offset_scale_chroma, 0, FFMAX(0, sps->bit_depth_chroma_minus8 - 2)); + + return 0; +} + +static int FUNC(pps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + int err, comp, i; + + flag(pps_curr_pic_ref_enabled_flag); + + flag(residual_adaptive_colour_transform_enabled_flag); + if (current->residual_adaptive_colour_transform_enabled_flag) { + flag(pps_slice_act_qp_offsets_present_flag); + se(pps_act_y_qp_offset_plus5, -7, +17); + se(pps_act_cb_qp_offset_plus5, -7, +17); + se(pps_act_cr_qp_offset_plus3, -9, +15); + } else { + infer(pps_slice_act_qp_offsets_present_flag, 0); + infer(pps_act_y_qp_offset_plus5, 0); + infer(pps_act_cb_qp_offset_plus5, 0); + infer(pps_act_cr_qp_offset_plus3, 0); + } + + flag(pps_palette_predictor_initializer_present_flag); + if (current->pps_palette_predictor_initializer_present_flag) { + ue(pps_num_palette_predictor_initializer, 0, 128); + if (current->pps_num_palette_predictor_initializer > 0) { + flag(monochrome_palette_flag); + ue(luma_bit_depth_entry_minus8, 0, 8); + if (!current->monochrome_palette_flag) + ue(chroma_bit_depth_entry_minus8, 0, 8); + for (comp = 0; comp < (current->monochrome_palette_flag ? 1 : 3); comp++) { + int bit_depth = comp == 0 ? current->luma_bit_depth_entry_minus8 + 8 + : current->chroma_bit_depth_entry_minus8 + 8; + for (i = 0; i < current->pps_num_palette_predictor_initializer; i++) + u(bit_depth, pps_palette_predictor_initializers[comp][i], + 0, (1 << bit_depth) - 1); + } + } + } + + return 0; +} + +static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + int err, i; + + HEADER("Picture Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_PPS)); + + ue(pps_pic_parameter_set_id, 0, 63); + ue(pps_seq_parameter_set_id, 0, 15); + sps = h265->sps[current->pps_seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->pps_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + flag(dependent_slice_segments_enabled_flag); + flag(output_flag_present_flag); + u(3, num_extra_slice_header_bits, 0, 7); + flag(sign_data_hiding_enabled_flag); + flag(cabac_init_present_flag); + + ue(num_ref_idx_l0_default_active_minus1, 0, 14); + ue(num_ref_idx_l1_default_active_minus1, 0, 14); + + se(init_qp_minus26, -(26 + 6 * sps->bit_depth_luma_minus8), +25); + + flag(constrained_intra_pred_flag); + flag(transform_skip_enabled_flag); + flag(cu_qp_delta_enabled_flag); + if (current->cu_qp_delta_enabled_flag) + ue(diff_cu_qp_delta_depth, + 0, sps->log2_diff_max_min_luma_coding_block_size); + else + infer(diff_cu_qp_delta_depth, 0); + + se(pps_cb_qp_offset, -12, +12); + se(pps_cr_qp_offset, -12, +12); + flag(pps_slice_chroma_qp_offsets_present_flag); + + flag(weighted_pred_flag); + flag(weighted_bipred_flag); + + flag(transquant_bypass_enabled_flag); + flag(tiles_enabled_flag); + flag(entropy_coding_sync_enabled_flag); + + if (current->tiles_enabled_flag) { + ue(num_tile_columns_minus1, 0, HEVC_MAX_TILE_COLUMNS); + ue(num_tile_rows_minus1, 0, HEVC_MAX_TILE_ROWS); + flag(uniform_spacing_flag); + if (!current->uniform_spacing_flag) { + for (i = 0; i < current->num_tile_columns_minus1; i++) + ue(column_width_minus1[i], 0, sps->pic_width_in_luma_samples); + for (i = 0; i < current->num_tile_rows_minus1; i++) + ue(row_height_minus1[i], 0, sps->pic_height_in_luma_samples); + } + flag(loop_filter_across_tiles_enabled_flag); + } else { + infer(num_tile_columns_minus1, 0); + infer(num_tile_rows_minus1, 0); + } + + flag(pps_loop_filter_across_slices_enabled_flag); + flag(deblocking_filter_control_present_flag); + if (current->deblocking_filter_control_present_flag) { + flag(deblocking_filter_override_enabled_flag); + flag(pps_deblocking_filter_disabled_flag); + if (!current->pps_deblocking_filter_disabled_flag) { + se(pps_beta_offset_div2, -6, +6); + se(pps_tc_offset_div2, -6, +6); + } else { + infer(pps_beta_offset_div2, 0); + infer(pps_tc_offset_div2, 0); + } + } else { + infer(deblocking_filter_override_enabled_flag, 0); + infer(pps_deblocking_filter_disabled_flag, 0); + infer(pps_beta_offset_div2, 0); + infer(pps_tc_offset_div2, 0); + } + + flag(pps_scaling_list_data_present_flag); + if (current->pps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + + flag(lists_modification_present_flag); + + ue(log2_parallel_merge_level_minus2, + 0, (sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size - 2)); + + flag(slice_segment_header_extension_present_flag); + + flag(pps_extension_present_flag); + if (current->pps_extension_present_flag) { + flag(pps_range_extension_flag); + flag(pps_multilayer_extension_flag); + flag(pps_3d_extension_flag); + flag(pps_scc_extension_flag); + u(4, pps_extension_4bits, 0, (1 << 4) - 1); + } + if (current->pps_range_extension_flag) + CHECK(FUNC(pps_range_extension)(ctx, rw, current)); + if (current->pps_multilayer_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->pps_3d_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->pps_scc_extension_flag) + CHECK(FUNC(pps_scc_extension)(ctx, rw, current)); + if (current->pps_extension_4bits) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawAUD *current) +{ + int err; + + HEADER("Access Unit Delimiter"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_AUD)); + + u(3, pic_type, 0, 2); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(ref_pic_lists_modification)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current, + unsigned int num_pic_total_curr) +{ + unsigned int entry_size; + int err, i; + + entry_size = av_log2(num_pic_total_curr - 1) + 1; + + flag(ref_pic_list_modification_flag_l0); + if (current->ref_pic_list_modification_flag_l0) { + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) + u(entry_size, list_entry_l0[i], 0, num_pic_total_curr - 1); + } + + if (current->slice_type == HEVC_SLICE_B) { + flag(ref_pic_list_modification_flag_l1); + if (current->ref_pic_list_modification_flag_l1) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) + u(entry_size, list_entry_l1[i], 0, num_pic_total_curr - 1); + } + } + + return 0; +} + +static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, i, j; + int chroma = !sps->separate_colour_plane_flag && + sps->chroma_format_idc != 0; + + ue(luma_log2_weight_denom, 0, 7); + if (chroma) + se(delta_chroma_log2_weight_denom, -7, 7); + else + infer(delta_chroma_log2_weight_denom, 0); + + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if (1 /* is not same POC and same layer_id */) + flag(luma_weight_l0_flag[i]); + else + infer(luma_weight_l0_flag[i], 0); + } + if (chroma) { + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if (1 /* is not same POC and same layer_id */) + flag(chroma_weight_l0_flag[i]); + else + infer(chroma_weight_l0_flag[i], 0); + } + } + + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if (current->luma_weight_l0_flag[i]) { + se(delta_luma_weight_l0[i], -128, +127); + se(luma_offset_l0[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1)); + } else { + infer(delta_luma_weight_l0[i], 0); + infer(luma_offset_l0[i], 0); + } + if (current->chroma_weight_l0_flag[i]) { + for (j = 0; j < 2; j++) { + se(delta_chroma_weight_l0[i][j], -128, +127); + se(chroma_offset_l0[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1)); + } + } else { + for (j = 0; j < 2; j++) { + infer(delta_chroma_weight_l0[i][j], 0); + infer(chroma_offset_l0[i][j], 0); + } + } + } + + if (current->slice_type == HEVC_SLICE_B) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if (1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) + flag(luma_weight_l1_flag[i]); + else + infer(luma_weight_l1_flag[i], 0); + } + if (chroma) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if (1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) + flag(chroma_weight_l1_flag[i]); + else + infer(chroma_weight_l1_flag[i], 0); + } + } + + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if (current->luma_weight_l1_flag[i]) { + se(delta_luma_weight_l1[i], -128, +127); + se(luma_offset_l1[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1)); + } else { + infer(delta_luma_weight_l1[i], 0); + infer(luma_offset_l1[i], 0); + } + if (current->chroma_weight_l1_flag[i]) { + for (j = 0; j < 2; j++) { + se(delta_chroma_weight_l1[i][j], -128, +127); + se(chroma_offset_l1[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1)); + } + } else { + for (j = 0; j < 2; j++) { + infer(delta_chroma_weight_l1[i][j], 0); + infer(chroma_offset_l1[i][j], 0); + } + } + } + } + + return 0; +} + +static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawPPS *pps; + unsigned int min_cb_log2_size_y, ctb_log2_size_y, ctb_size_y; + unsigned int pic_width_in_ctbs_y, pic_height_in_ctbs_y, pic_size_in_ctbs_y; + unsigned int num_pic_total_curr = 0; + int err, i; + + HEADER("Slice Segment Header"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, -1)); + + flag(first_slice_segment_in_pic_flag); + + if (current->nal_unit_header.nal_unit_type >= HEVC_NAL_BLA_W_LP && + current->nal_unit_header.nal_unit_type <= HEVC_NAL_IRAP_VCL23) + flag(no_output_of_prior_pics_flag); + + ue(slice_pic_parameter_set_id, 0, 63); + + pps = h265->pps[current->slice_pic_parameter_set_id]; + if (!pps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "PPS id %d not available.\n", + current->slice_pic_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_pps = pps; + + sps = h265->sps[pps->pps_seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + pps->pps_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; + ctb_log2_size_y = min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_y = 1 << ctb_log2_size_y; + pic_width_in_ctbs_y = + (sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y; + pic_height_in_ctbs_y = + (sps->pic_height_in_luma_samples + ctb_size_y - 1) / ctb_size_y; + pic_size_in_ctbs_y = pic_width_in_ctbs_y * pic_height_in_ctbs_y; + + if (!current->first_slice_segment_in_pic_flag) { + unsigned int address_size = av_log2(pic_size_in_ctbs_y - 1) + 1; + if (pps->dependent_slice_segments_enabled_flag) + flag(dependent_slice_segment_flag); + else + infer(dependent_slice_segment_flag, 0); + u(address_size, slice_segment_address, 0, pic_size_in_ctbs_y - 1); + } else { + infer(dependent_slice_segment_flag, 0); + } + + if (!current->dependent_slice_segment_flag) { + for (i = 0; i < pps->num_extra_slice_header_bits; i++) + flag(slice_reserved_flag[i]); + + ue(slice_type, 0, 2); + + if (pps->output_flag_present_flag) + flag(pic_output_flag); + + if (sps->separate_colour_plane_flag) + u(2, colour_plane_id, 0, 2); + + if (current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_W_RADL && + current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_N_LP) { + const H265RawSTRefPicSet *rps; + + u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, slice_pic_order_cnt_lsb, + 0, (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1); + + flag(short_term_ref_pic_set_sps_flag); + if (!current->short_term_ref_pic_set_sps_flag) { + CHECK(FUNC(st_ref_pic_set)(ctx, rw, ¤t->short_term_ref_pic_set, + sps->num_short_term_ref_pic_sets, sps)); + rps = ¤t->short_term_ref_pic_set; + } else if (sps->num_short_term_ref_pic_sets > 1) { + unsigned int idx_size = av_log2(sps->num_short_term_ref_pic_sets - 1) + 1; + u(idx_size, short_term_ref_pic_set_idx, + 0, sps->num_short_term_ref_pic_sets - 1); + rps = &sps->st_ref_pic_set[current->short_term_ref_pic_set_idx]; + } else { + infer(short_term_ref_pic_set_idx, 0); + rps = &sps->st_ref_pic_set[0]; + } + + num_pic_total_curr = 0; + for (i = 0; i < rps->num_negative_pics; i++) + if (rps->used_by_curr_pic_s0_flag[i]) + ++num_pic_total_curr; + for (i = 0; i < rps->num_positive_pics; i++) + if (rps->used_by_curr_pic_s1_flag[i]) + ++num_pic_total_curr; + + if (sps->long_term_ref_pics_present_flag) { + unsigned int idx_size; + + if (sps->num_long_term_ref_pics_sps > 0) { + ue(num_long_term_sps, 0, sps->num_long_term_ref_pics_sps); + idx_size = av_log2(sps->num_long_term_ref_pics_sps - 1) + 1; + } else { + infer(num_long_term_sps, 0); + idx_size = 0; + } + ue(num_long_term_pics, 0, HEVC_MAX_LONG_TERM_REF_PICS); + + for (i = 0; i < current->num_long_term_sps + + current->num_long_term_pics; i++) { + if (i < current->num_long_term_sps) { + if (sps->num_long_term_ref_pics_sps > 1) + u(idx_size, lt_idx_sps[i], + 0, sps->num_long_term_ref_pics_sps - 1); + if (sps->used_by_curr_pic_lt_sps_flag[current->lt_idx_sps[i]]) + ++num_pic_total_curr; + } else { + u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, poc_lsb_lt[i], + 0, (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1); + flag(used_by_curr_pic_lt_flag[i]); + if (current->used_by_curr_pic_lt_flag[i]) + ++num_pic_total_curr; + } + flag(delta_poc_msb_present_flag[i]); + if (current->delta_poc_msb_present_flag[i]) + ue(delta_poc_msb_cycle_lt[i], 0, UINT32_MAX - 1); + else + infer(delta_poc_msb_cycle_lt[i], 0); + } + } + + if (sps->sps_temporal_mvp_enabled_flag) + flag(slice_temporal_mvp_enabled_flag); + else + infer(slice_temporal_mvp_enabled_flag, 0); + + if (pps->pps_curr_pic_ref_enabled_flag) + ++num_pic_total_curr; + } + + if (sps->sample_adaptive_offset_enabled_flag) { + flag(slice_sao_luma_flag); + if (!sps->separate_colour_plane_flag && sps->chroma_format_idc != 0) + flag(slice_sao_chroma_flag); + else + infer(slice_sao_chroma_flag, 0); + } else { + infer(slice_sao_luma_flag, 0); + infer(slice_sao_chroma_flag, 0); + } + + if (current->slice_type == HEVC_SLICE_P || + current->slice_type == HEVC_SLICE_B) { + flag(num_ref_idx_active_override_flag); + if (current->num_ref_idx_active_override_flag) { + ue(num_ref_idx_l0_active_minus1, 0, 14); + if (current->slice_type == HEVC_SLICE_B) + ue(num_ref_idx_l1_active_minus1, 0, 14); + else + infer(num_ref_idx_l1_active_minus1, pps->num_ref_idx_l1_default_active_minus1); + } else { + infer(num_ref_idx_l0_active_minus1, pps->num_ref_idx_l0_default_active_minus1); + infer(num_ref_idx_l1_active_minus1, pps->num_ref_idx_l1_default_active_minus1); + } + + if (pps->lists_modification_present_flag && num_pic_total_curr > 1) + CHECK(FUNC(ref_pic_lists_modification)(ctx, rw, current, + num_pic_total_curr)); + + if (current->slice_type == HEVC_SLICE_B) + flag(mvd_l1_zero_flag); + if (pps->cabac_init_present_flag) + flag(cabac_init_flag); + else + infer(cabac_init_flag, 0); + if (current->slice_temporal_mvp_enabled_flag) { + if (current->slice_type == HEVC_SLICE_B) + flag(collocated_from_l0_flag); + else + infer(collocated_from_l0_flag, 1); + if (current->collocated_from_l0_flag) { + if (current->num_ref_idx_l0_active_minus1 > 0) + ue(collocated_ref_idx, 0, current->num_ref_idx_l0_active_minus1); + else + infer(collocated_ref_idx, 0); + } else { + if (current->num_ref_idx_l1_active_minus1 > 0) + ue(collocated_ref_idx, 0, current->num_ref_idx_l1_active_minus1); + else + infer(collocated_ref_idx, 0); + } + } + + if ((pps->weighted_pred_flag && current->slice_type == HEVC_SLICE_P) || + (pps->weighted_bipred_flag && current->slice_type == HEVC_SLICE_B)) + CHECK(FUNC(pred_weight_table)(ctx, rw, current)); + + ue(five_minus_max_num_merge_cand, 0, 4); + if (sps->motion_vector_resolution_control_idc == 2) + flag(use_integer_mv_flag); + else + infer(use_integer_mv_flag, sps->motion_vector_resolution_control_idc); + } + + se(slice_qp_delta, + - 6 * sps->bit_depth_luma_minus8 - (pps->init_qp_minus26 + 26), + + 51 - (pps->init_qp_minus26 + 26)); + if (pps->pps_slice_chroma_qp_offsets_present_flag) { + se(slice_cb_qp_offset, -12, +12); + se(slice_cr_qp_offset, -12, +12); + } else { + infer(slice_cb_qp_offset, 0); + infer(slice_cr_qp_offset, 0); + } + if (pps->pps_slice_act_qp_offsets_present_flag) { + se(slice_act_y_qp_offset, + -12 - (pps->pps_act_y_qp_offset_plus5 - 5), + +12 - (pps->pps_act_y_qp_offset_plus5 - 5)); + se(slice_act_cb_qp_offset, + -12 - (pps->pps_act_cb_qp_offset_plus5 - 5), + +12 - (pps->pps_act_cb_qp_offset_plus5 - 5)); + se(slice_act_cr_qp_offset, + -12 - (pps->pps_act_cr_qp_offset_plus3 - 3), + +12 - (pps->pps_act_cr_qp_offset_plus3 - 3)); + } else { + infer(slice_act_y_qp_offset, 0); + infer(slice_act_cb_qp_offset, 0); + infer(slice_act_cr_qp_offset, 0); + } + if (pps->chroma_qp_offset_list_enabled_flag) + flag(cu_chroma_qp_offset_enabled_flag); + else + infer(cu_chroma_qp_offset_enabled_flag, 0); + + if (pps->deblocking_filter_override_enabled_flag) + flag(deblocking_filter_override_flag); + else + infer(deblocking_filter_override_flag, 0); + if (current->deblocking_filter_override_flag) { + flag(slice_deblocking_filter_disabled_flag); + if (!current->slice_deblocking_filter_disabled_flag) { + se(slice_beta_offset_div2, -6, +6); + se(slice_tc_offset_div2, -6, +6); + } else { + infer(slice_beta_offset_div2, pps->pps_beta_offset_div2); + infer(slice_tc_offset_div2, pps->pps_tc_offset_div2); + } + } else { + infer(slice_deblocking_filter_disabled_flag, + pps->pps_deblocking_filter_disabled_flag); + infer(slice_beta_offset_div2, pps->pps_beta_offset_div2); + infer(slice_tc_offset_div2, pps->pps_tc_offset_div2); + } + if (pps->pps_loop_filter_across_slices_enabled_flag && + (current->slice_sao_luma_flag || current->slice_sao_chroma_flag || + !current->slice_deblocking_filter_disabled_flag)) + flag(slice_loop_filter_across_slices_enabled_flag); + else + infer(slice_loop_filter_across_slices_enabled_flag, + pps->pps_loop_filter_across_slices_enabled_flag); + } + + if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) { + unsigned int num_entry_point_offsets_limit; + if (!pps->tiles_enabled_flag && pps->entropy_coding_sync_enabled_flag) + num_entry_point_offsets_limit = pic_height_in_ctbs_y - 1; + else if (pps->tiles_enabled_flag && !pps->entropy_coding_sync_enabled_flag) + num_entry_point_offsets_limit = + (pps->num_tile_columns_minus1 + 1) * (pps->num_tile_rows_minus1 + 1); + else + num_entry_point_offsets_limit = + (pps->num_tile_columns_minus1 + 1) * pic_height_in_ctbs_y - 1; + ue(num_entry_point_offsets, 0, num_entry_point_offsets_limit); + + if (current->num_entry_point_offsets > HEVC_MAX_ENTRY_POINT_OFFSETS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many entry points: " + "%"PRIu16".\n", current->num_entry_point_offsets); + return AVERROR_PATCHWELCOME; + } + + if (current->num_entry_point_offsets > 0) { + ue(offset_len_minus1, 0, 31); + for (i = 0; i < current->num_entry_point_offsets; i++) + u(current->offset_len_minus1 + 1, entry_point_offset_minus1[i], + 0, (1 << (current->offset_len_minus1 + 1)) - 1); + } + } + + if (pps->slice_segment_header_extension_present_flag) { + ue(slice_segment_header_extension_length, 0, 256); + for (i = 0; i < current->slice_segment_header_extension_length; i++) + u(8, slice_segment_header_extension_data_byte[i], 0x00, 0xff); + } + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + return 0; +} diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h new file mode 100644 index 000000000..ae0b417b4 --- /dev/null +++ b/libavcodec/cbs_internal.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 AVCODEC_CBS_INTERNAL_H +#define AVCODEC_CBS_INTERNAL_H + +#include "avcodec.h" +#include "cbs.h" +#include "get_bits.h" +#include "put_bits.h" + + +typedef struct CodedBitstreamType { + enum AVCodecID codec_id; + + size_t priv_data_size; + + // Split frag->data into coded bitstream units, creating the + // frag->units array. Fill data but not content on each unit. + // header is set if the fragment came from a header block, which + // may require different parsing for some codecs (e.g. the AVCC + // header in H.264). + int (*split_fragment)(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header); + + // Read the unit->data bitstream and decompose it, creating + // unit->content. + int (*read_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + // Write the unit->data bitstream from unit->content. + int (*write_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + // Read the data from all of frag->units and assemble it into + // a bitstream for the whole fragment. + int (*assemble_fragment)(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + + // Free the content and data of a single unit. + void (*free_unit)(CodedBitstreamUnit *unit); + + // Free the codec internal state. + void (*close)(CodedBitstreamContext *ctx); +} CodedBitstreamType; + + +// Helper functions for trace output. + +void ff_cbs_trace_header(CodedBitstreamContext *ctx, + const char *name); + +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, + int position, const char *name, + const char *bitstring, int64_t value); + + +// Helper functions for read/write of common bitstream elements, including +// generation of trace output. + +int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max); + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max); + + +extern const CodedBitstreamType ff_cbs_type_h264; +extern const CodedBitstreamType ff_cbs_type_h265; +extern const CodedBitstreamType ff_cbs_type_mpeg2; + + +#endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c new file mode 100644 index 000000000..642a9c99b --- /dev/null +++ b/libavcodec/cbs_mpeg2.c @@ -0,0 +1,414 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "cbs.h" +#include "cbs_internal.h" +#include "cbs_mpeg2.h" +#include "internal.h" + + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_MPEG2(rw, name) FUNC_NAME(rw, mpeg2, name) +#define FUNC(name) FUNC_MPEG2(READWRITE, name) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xui(width, name, var) do { \ + uint32_t value = 0; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + &value, 0, (1 << width) - 1)); \ + var = value; \ + } while (0) + +#define ui(width, name) \ + xui(width, name, current->name) + +#define marker_bit() do { \ + av_unused uint32_t one; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, 1, "marker_bit", &one, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) \ + (get_bits_left(rw) >= width && \ + (var = show_bits(rw, width)) == (compare)) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xui +#undef ui +#undef marker_bit +#undef nextbits + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xui(width, name, var) do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + var, 0, (1 << width) - 1)); \ + } while (0) + +#define ui(width, name) \ + xui(width, name, current->name) + +#define marker_bit() do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, 1, "marker_bit", 1, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) (var) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xui +#undef ui +#undef marker_bit +#undef nextbits + + +static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + const uint8_t *start, *end; + uint8_t *unit_data; + uint32_t start_code = -1, next_start_code = -1; + size_t unit_size; + int err, i, unit_type; + + start = avpriv_find_start_code(frag->data, frag->data + frag->data_size, + &start_code); + for (i = 0;; i++) { + end = avpriv_find_start_code(start, frag->data + frag->data_size, + &next_start_code); + + unit_type = start_code & 0xff; + + // The start and end pointers point at to the byte following the + // start_code_identifier in the start code that they found. + if (end == frag->data + frag->data_size) { + // We didn't find a start code, so this is the final unit. + unit_size = end - (start - 1); + } else { + // Unit runs from start to the beginning of the start code + // pointed to by end (including any padding zeroes). + unit_size = (end - 4) - (start - 1); + } + + unit_data = av_malloc(unit_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!unit_data) + return AVERROR(ENOMEM); + memcpy(unit_data, start - 1, unit_size); + memset(unit_data + unit_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + err = ff_cbs_insert_unit_data(ctx, frag, i, unit_type, + unit_data, unit_size); + if (err < 0) { + av_freep(&unit_data); + return err; + } + + if (end == frag->data + frag->data_size) + break; + + start_code = next_start_code; + start = end; + } + + return 0; +} + +static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + if (MPEG2_START_IS_SLICE(unit->type)) { + MPEG2RawSlice *slice; + int pos, len; + + slice = av_mallocz(sizeof(*slice)); + if (!slice) + return AVERROR(ENOMEM); + err = cbs_mpeg2_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) { + av_free(slice); + return err; + } + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data = av_malloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data) { + av_free(slice); + return AVERROR(ENOMEM); + } + + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + + unit->content = slice; + + } else { + switch (unit->type) { +#define START(start_code, type, func) \ + case start_code: \ + { \ + type *header; \ + header = av_mallocz(sizeof(*header)); \ + if (!header) \ + return AVERROR(ENOMEM); \ + err = cbs_mpeg2_read_ ## func(ctx, &gbc, header); \ + if (err < 0) { \ + av_free(header); \ + return err; \ + } \ + unit->content = header; \ + } \ + break; + START(0x00, MPEG2RawPictureHeader, picture_header); + START(0xb2, MPEG2RawUserData, user_data); + START(0xb3, MPEG2RawSequenceHeader, sequence_header); + START(0xb5, MPEG2RawExtensionData, extension_data); + START(0xb8, MPEG2RawGroupOfPicturesHeader, group_of_pictures_header); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unknown start code %"PRIx32".\n", + unit->type); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int cbs_mpeg2_write_header(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { +#define START(start_code, type, func) \ + case start_code: \ + err = cbs_mpeg2_write_ ## func(ctx, pbc, unit->content); \ + break; + START(0x00, MPEG2RawPictureHeader, picture_header); + START(0xb2, MPEG2RawUserData, user_data); + START(0xb3, MPEG2RawSequenceHeader, sequence_header); + START(0xb5, MPEG2RawExtensionData, extension_data); + START(0xb8, MPEG2RawGroupOfPicturesHeader, group_of_pictures_header); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for start " + "code %02"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return err; +} + +static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + MPEG2RawSlice *slice = unit->content; + GetBitContext gbc; + size_t bits_left; + int err; + + err = cbs_mpeg2_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + while (get_bits_left(&gbc) > 15) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + put_bits(pbc, bits_left, get_bits(&gbc, bits_left)); + + // Align with zeroes. + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } + + return 0; +} + +static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamMPEG2Context *priv = ctx->priv_data; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + if (unit->type >= 0x01 && unit->type <= 0xaf) + err = cbs_mpeg2_write_slice(ctx, unit, &pbc); + else + err = cbs_mpeg2_write_header(ctx, unit, &pbc); + + if (err == AVERROR(ENOSPC)) { + // Overflow. + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + if (err < 0) { + // Write failed for some other reason. + return err; + } + + if (put_bits_count(&pbc) % 8) + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; + else + unit->data_bit_padding = 0; + + unit->data_size = (put_bits_count(&pbc) + 7) / 8; + flush_put_bits(&pbc); + + err = av_reallocp(&unit->data, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + uint8_t *data; + size_t size, dp, sp; + int i; + + size = 0; + for (i = 0; i < frag->nb_units; i++) + size += 3 + frag->units[i].data_size; + + data = av_malloc(size); + if (!data) + return AVERROR(ENOMEM); + + dp = 0; + for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + for (sp = 0; sp < unit->data_size; sp++) + data[dp++] = unit->data[sp]; + } + + av_assert0(dp == size); + + frag->data = data; + frag->data_size = size; + + return 0; +} + +static void cbs_mpeg2_free_unit(CodedBitstreamUnit *unit) +{ + if (MPEG2_START_IS_SLICE(unit->type)) { + MPEG2RawSlice *slice = unit->content; + av_freep(&slice->data); + av_freep(&slice->header.extra_information); + } else if (unit->type == MPEG2_START_USER_DATA) { + MPEG2RawUserData *user = unit->content; + av_freep(&user->user_data); + } + av_freep(&unit->content); +} + +static void cbs_mpeg2_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamMPEG2Context *priv = ctx->priv_data; + + av_freep(&priv->write_buffer); +} + +const CodedBitstreamType ff_cbs_type_mpeg2 = { + .codec_id = AV_CODEC_ID_MPEG2VIDEO, + + .priv_data_size = sizeof(CodedBitstreamMPEG2Context), + + .split_fragment = &cbs_mpeg2_split_fragment, + .read_unit = &cbs_mpeg2_read_unit, + .write_unit = &cbs_mpeg2_write_unit, + .assemble_fragment = &cbs_mpeg2_assemble_fragment, + + .free_unit = &cbs_mpeg2_free_unit, + .close = &cbs_mpeg2_close, +}; diff --git a/libavcodec/cbs_mpeg2.h b/libavcodec/cbs_mpeg2.h new file mode 100644 index 000000000..a8f12b2e7 --- /dev/null +++ b/libavcodec/cbs_mpeg2.h @@ -0,0 +1,224 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CBS_MPEG2_H +#define AVCODEC_CBS_MPEG2_H + +#include +#include + + +enum { + MPEG2_START_PICTURE = 0x00, + MPEG2_START_SLICE_MIN = 0x01, + MPEG2_START_SLICE_MAX = 0xaf, + MPEG2_START_USER_DATA = 0xb2, + MPEG2_START_SEQUENCE_HEADER = 0xb3, + MPEG2_START_SEQUENCE_ERROR = 0xb4, + MPEG2_START_EXTENSION = 0xb5, + MPEG2_START_SEQUENCE_END = 0xb7, + MPEG2_START_GROUP = 0xb8, +}; + +#define MPEG2_START_IS_SLICE(type) \ + ((type) >= MPEG2_START_SLICE_MIN && \ + (type) <= MPEG2_START_SLICE_MAX) + +enum { + MPEG2_EXTENSION_SEQUENCE = 0x1, + MPEG2_EXTENSION_SEQUENCE_DISPLAY = 0x2, + MPEG2_EXTENSION_QUANT_MATRIX = 0x3, + MPEG2_EXTENSION_COPYRIGHT = 0x4, + MPEG2_EXTENSION_SEQUENCE_SCALABLE = 0x5, + MPEG2_EXTENSION_PICTURE_DISPLAY = 0x7, + MPEG2_EXTENSION_PICTURE_CODING = 0x8, + MPEG2_EXTENSION_PICTURE_SPATIAL_SCALABLE = 0x9, + MPEG2_EXTENSION_PICTURE_TEMPORAL_SCALABLE = 0xa, + MPEG2_EXTENSION_CAMAERA_PARAMETERS = 0xb, + MPEG2_EXTENSION_ITU_T = 0xc, +}; + + +typedef struct MPEG2RawSequenceHeader { + uint8_t sequence_header_code; + + uint16_t horizontal_size_value; + uint16_t vertical_size_value; + uint8_t aspect_ratio_information; + uint8_t frame_rate_code; + uint32_t bit_rate_value; + uint16_t vbv_buffer_size_value; + uint8_t constrained_parameters_flag; + + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; +} MPEG2RawSequenceHeader; + +typedef struct MPEG2RawUserData { + uint8_t user_data_start_code; + + uint8_t *user_data; + size_t user_data_length; +} MPEG2RawUserData; + +typedef struct MPEG2RawSequenceExtension { + uint8_t profile_and_level_indication; + uint8_t progressive_sequence; + uint8_t chroma_format; + uint8_t horizontal_size_extension; + uint8_t vertical_size_extension; + uint16_t bit_rate_extension; + uint8_t vbv_buffer_size_extension; + uint8_t low_delay; + uint8_t frame_rate_extension_n; + uint8_t frame_rate_extension_d; +} MPEG2RawSequenceExtension; + +typedef struct MPEG2RawSequenceDisplayExtension { + uint8_t video_format; + + uint8_t colour_description; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint16_t display_horizontal_size; + uint16_t display_vertical_size; +} MPEG2RawSequenceDisplayExtension; + +typedef struct MPEG2RawGroupOfPicturesHeader { + uint8_t group_start_code; + + uint32_t time_code; + uint8_t closed_gop; + uint8_t broken_link; +} MPEG2RawGroupOfPicturesHeader; + +typedef struct MPEG2RawPictureHeader { + uint8_t picture_start_code; + + uint16_t temporal_reference; + uint8_t picture_coding_type; + uint16_t vbv_delay; + + uint8_t full_pel_forward_vector; + uint8_t forward_f_code; + uint8_t full_pel_backward_vector; + uint8_t backward_f_code; + + uint8_t extra_bit_picture; +} MPEG2RawPictureHeader; + +typedef struct MPEG2RawPictureCodingExtension { + uint8_t f_code[2][2]; + + uint8_t intra_dc_precision; + uint8_t picture_structure; + uint8_t top_field_first; + uint8_t frame_pred_frame_dct; + uint8_t concealment_motion_vectors; + uint8_t q_scale_type; + uint8_t intra_vlc_format; + uint8_t alternate_scan; + uint8_t repeat_first_field; + uint8_t chroma_420_type; + uint8_t progressive_frame; + + uint8_t composite_display_flag; + uint8_t v_axis; + uint8_t field_sequence; + uint8_t sub_carrier; + uint8_t burst_amplitude; + uint8_t sub_carrier_phase; +} MPEG2RawPictureCodingExtension; + +typedef struct MPEG2RawQuantMatrixExtension { + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; + uint8_t load_chroma_intra_quantiser_matrix; + uint8_t chroma_intra_quantiser_matrix[64]; + uint8_t load_chroma_non_intra_quantiser_matrix; + uint8_t chroma_non_intra_quantiser_matrix[64]; +} MPEG2RawQuantMatrixExtension; + +typedef struct MPEG2RawPictureDisplayExtension { + uint16_t frame_centre_horizontal_offset[3]; + uint16_t frame_centre_vertical_offset[3]; +} MPEG2RawPictureDisplayExtension; + +typedef struct MPEG2RawExtensionData { + uint8_t extension_start_code; + uint8_t extension_start_code_identifier; + + union { + MPEG2RawSequenceExtension sequence; + MPEG2RawSequenceDisplayExtension sequence_display; + MPEG2RawQuantMatrixExtension quant_matrix; + MPEG2RawPictureCodingExtension picture_coding; + MPEG2RawPictureDisplayExtension picture_display; + } data; +} MPEG2RawExtensionData; + +typedef struct MPEG2RawSliceHeader { + uint8_t slice_vertical_position; + + uint8_t slice_vertical_position_extension; + uint8_t priority_breakpoint; + + uint8_t quantiser_scale_code; + + uint8_t slice_extension_flag; + uint8_t intra_slice; + uint8_t slice_picture_id_enable; + uint8_t slice_picture_id; + + uint8_t extra_bit_slice; + + size_t extra_information_length; + uint8_t *extra_information; +} MPEG2RawSliceHeader; + +typedef struct MPEG2RawSlice { + MPEG2RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; +} MPEG2RawSlice; + + +typedef struct CodedBitstreamMPEG2Context { + // Elements stored in headers which are required for other decoding. + uint16_t horizontal_size; + uint16_t vertical_size; + uint8_t scalable; + uint8_t scalable_mode; + uint8_t progressive_sequence; + uint8_t number_of_frame_centre_offsets; + + // Write buffer. + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamMPEG2Context; + + +#endif /* AVCODEC_CBS_MPEG2_H */ diff --git a/libavcodec/cbs_mpeg2_syntax_template.c b/libavcodec/cbs_mpeg2_syntax_template.c new file mode 100644 index 000000000..90dde26ae --- /dev/null +++ b/libavcodec/cbs_mpeg2_syntax_template.c @@ -0,0 +1,384 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 int FUNC(sequence_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceHeader *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Sequence Header"); + + ui(8, sequence_header_code); + + ui(12, horizontal_size_value); + ui(12, vertical_size_value); + + mpeg2->horizontal_size = current->horizontal_size_value; + mpeg2->vertical_size = current->vertical_size_value; + + ui(4, aspect_ratio_information); + ui(4, frame_rate_code); + ui(18, bit_rate_value); + + marker_bit(); + + ui(10, vbv_buffer_size_value); + ui(1, constrained_parameters_flag); + + ui(1, load_intra_quantiser_matrix); + if (current->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_non_intra_quantiser_matrix); + if (current->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, non_intra_quantiser_matrix[i]); + } + + return 0; +} + +static int FUNC(user_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawUserData *current) +{ + size_t k; + int err; + + HEADER("User Data"); + + ui(8, user_data_start_code); + +#ifdef READ + k = get_bits_left(rw); + av_assert0(k % 8 == 0); + current->user_data_length = k /= 8; + if (k > 0) { + current->user_data = av_malloc(k); + if (!current->user_data) + return AVERROR(ENOMEM); + } +#endif + + for (k = 0; k < current->user_data_length; k++) + xui(8, user_data, current->user_data[k]); + + return 0; +} + +static int FUNC(sequence_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Sequence Extension"); + + ui(8, profile_and_level_indication); + ui(1, progressive_sequence); + ui(2, chroma_format); + ui(2, horizontal_size_extension); + ui(2, vertical_size_extension); + + mpeg2->horizontal_size = (mpeg2->horizontal_size & 0xfff) | + current->horizontal_size_extension << 12; + mpeg2->vertical_size = (mpeg2->vertical_size & 0xfff) | + current->vertical_size_extension << 12; + mpeg2->progressive_sequence = current->progressive_sequence; + + ui(12, bit_rate_extension); + marker_bit(); + ui(8, vbv_buffer_size_extension); + ui(1, low_delay); + ui(2, frame_rate_extension_n); + ui(5, frame_rate_extension_d); + + return 0; +} + +static int FUNC(sequence_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceDisplayExtension *current) +{ + int err; + + HEADER("Sequence Display Extension"); + + ui(3, video_format); + + ui(1, colour_description); + if (current->colour_description) { + ui(8, colour_primaries); + ui(8, transfer_characteristics); + ui(8, matrix_coefficients); + } + + ui(14, display_horizontal_size); + marker_bit(); + ui(14, display_vertical_size); + + return 0; +} + +static int FUNC(group_of_pictures_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawGroupOfPicturesHeader *current) +{ + int err; + + HEADER("Group of Pictures Header"); + + ui(8, group_start_code); + + ui(25, time_code); + ui(1, closed_gop); + ui(1, broken_link); + + return 0; +} + +static int FUNC(picture_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureHeader *current) +{ + int err; + + HEADER("Picture Header"); + + ui(8, picture_start_code); + + ui(10, temporal_reference); + ui(3, picture_coding_type); + ui(16, vbv_delay); + + if (current->picture_coding_type == 2 || + current->picture_coding_type == 3) { + ui(1, full_pel_forward_vector); + ui(3, forward_f_code); + } + + if (current->picture_coding_type == 3) { + ui(1, full_pel_backward_vector); + ui(3, backward_f_code); + } + + ui(1, extra_bit_picture); + + return 0; +} + +static int FUNC(picture_coding_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureCodingExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Picture Coding Extension"); + + ui(4, f_code[0][0]); + ui(4, f_code[0][1]); + ui(4, f_code[1][0]); + ui(4, f_code[1][1]); + + ui(2, intra_dc_precision); + ui(2, picture_structure); + ui(1, top_field_first); + ui(1, frame_pred_frame_dct); + ui(1, concealment_motion_vectors); + ui(1, q_scale_type); + ui(1, intra_vlc_format); + ui(1, alternate_scan); + ui(1, repeat_first_field); + ui(1, chroma_420_type); + ui(1, progressive_frame); + + if (mpeg2->progressive_sequence) { + if (current->repeat_first_field) { + if (current->top_field_first) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } else { + mpeg2->number_of_frame_centre_offsets = 1; + } + } else { + if (current->picture_structure == 1 || // Top field. + current->picture_structure == 2) { // Bottom field. + mpeg2->number_of_frame_centre_offsets = 1; + } else { + if (current->repeat_first_field) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } + } + + ui(1, composite_display_flag); + if (current->composite_display_flag) { + ui(1, v_axis); + ui(3, field_sequence); + ui(1, sub_carrier); + ui(7, burst_amplitude); + ui(8, sub_carrier_phase); + } + + return 0; +} + +static int FUNC(quant_matrix_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawQuantMatrixExtension *current) +{ + int err, i; + + HEADER("Quant Matrix Extension"); + + ui(1, load_intra_quantiser_matrix); + if (current->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_non_intra_quantiser_matrix); + if (current->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, non_intra_quantiser_matrix[i]); + } + + ui(1, load_chroma_intra_quantiser_matrix); + if (current->load_chroma_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_chroma_non_intra_quantiser_matrix); + if (current->load_chroma_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, chroma_non_intra_quantiser_matrix[i]); + } + + return 0; +} + +static int FUNC(picture_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureDisplayExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Picture Display Extension"); + + for (i = 0; i < mpeg2->number_of_frame_centre_offsets; i++) { + ui(16, frame_centre_horizontal_offset[i]); + marker_bit(); + ui(16, frame_centre_vertical_offset[i]); + marker_bit(); + } + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawExtensionData *current) +{ + int err; + + HEADER("Extension Data"); + + ui(8, extension_start_code); + ui(4, extension_start_code_identifier); + + switch (current->extension_start_code_identifier) { + case 1: + return FUNC(sequence_extension) + (ctx, rw, ¤t->data.sequence); + case 2: + return FUNC(sequence_display_extension) + (ctx, rw, ¤t->data.sequence_display); + case 3: + return FUNC(quant_matrix_extension) + (ctx, rw, ¤t->data.quant_matrix); + case 7: + return FUNC(picture_display_extension) + (ctx, rw, ¤t->data.picture_display); + case 8: + return FUNC(picture_coding_extension) + (ctx, rw, ¤t->data.picture_coding); + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid extension ID %d.\n", + current->extension_start_code_identifier); + return AVERROR_INVALIDDATA; + } +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSliceHeader *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Slice Header"); + + ui(8, slice_vertical_position); + + if (mpeg2->vertical_size > 2800) + ui(3, slice_vertical_position_extension); + if (mpeg2->scalable) { + if (mpeg2->scalable_mode == 0) + ui(7, priority_breakpoint); + } + + ui(5, quantiser_scale_code); + + if (nextbits(1, 1, current->slice_extension_flag)) { + ui(1, slice_extension_flag); + ui(1, intra_slice); + ui(1, slice_picture_id_enable); + ui(6, slice_picture_id); + + { + size_t k; +#ifdef READ + GetBitContext start; + uint8_t bit; + start = *rw; + for (k = 0; nextbits(1, 1, bit); k++) + skip_bits(rw, 8); + current->extra_information_length = k; + if (k > 0) { + *rw = start; + current->extra_information = + av_malloc(current->extra_information_length); + if (!current->extra_information) + return AVERROR(ENOMEM); + for (k = 0; k < current->extra_information_length; k++) { + xui(1, extra_bit_slice, bit); + xui(8, extra_information_slice, + current->extra_information[k]); + } + } +#else + for (k = 0; k < current->extra_information_length; k++) { + xui(1, extra_bit_slice, 1); + xui(8, extra_information_slice, current->extra_information[k]); + } +#endif + } + } + ui(1, extra_bit_slice); + + return 0; +} diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index 5ea8f2482..fd5555834 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -20,24 +20,39 @@ /** * @file - * CFHD Video Decoder + * Cineform HD video decoder */ +#include "libavutil/attributes.h" #include "libavutil/buffer.h" #include "libavutil/common.h" -#include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "avcodec.h" -#include "internal.h" #include "bytestream.h" +#include "get_bits.h" +#include "internal.h" #include "thread.h" #include "cfhd.h" -#define SUBBAND_COUNT 10 +enum CFHDParam { + ChannelCount = 12, + SubbandCount = 14, + ImageWidth = 20, + ImageHeight = 21, + LowpassPrecision = 35, + SubbandNumber = 48, + Quantization = 53, + ChannelNumber = 62, + BitsPerComponent = 101, + ChannelWidth = 104, + ChannelHeight = 105, + PrescaleShift = 109, +}; -static av_cold int cfhd_decode_init(AVCodecContext *avctx) +static av_cold int cfhd_init(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; @@ -58,9 +73,10 @@ static void init_frame_defaults(CFHDContext *s) { s->coded_width = 0; s->coded_height = 0; + s->cropped_height = 0; s->bpc = 10; s->channel_cnt = 4; - s->subband_cnt = 10; + s->subband_cnt = SUBBAND_COUNT; s->channel_num = 0; s->lowpass_precision = 16; s->quantisation = 1; @@ -74,15 +90,18 @@ static void init_frame_defaults(CFHDContext *s) static inline int dequant_and_decompand(int level, int quantisation) { int64_t abslevel = abs(level); - return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) * FFSIGN(level) * quantisation; + return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) * + FFSIGN(level) * quantisation; } -static inline void filter(int16_t *output, ptrdiff_t out_stride, int16_t *low, ptrdiff_t low_stride, - int16_t *high, ptrdiff_t high_stride, int len, uint8_t clip) +static inline void filter(int16_t *output, ptrdiff_t out_stride, + int16_t *low, ptrdiff_t low_stride, + int16_t *high, ptrdiff_t high_stride, + int len, int clip) { int16_t tmp; - int i; + for (i = 0; i < len; i++) { if (i == 0) { tmp = (11*low[0*low_stride] - 4*low[1*low_stride] + low[2*low_stride] + 4) >> 3; @@ -118,28 +137,30 @@ static inline void filter(int16_t *output, ptrdiff_t out_stride, int16_t *low, p } } -static void horiz_filter(int16_t *output, int16_t *low, int16_t *high, int width) +static void horiz_filter(int16_t *output, int16_t *low, int16_t *high, + int width) { filter(output, 1, low, 1, high, 1, width, 0); } -static void horiz_filter_clip(int16_t *output, int16_t *low, int16_t *high, int width, uint8_t clip) +static void horiz_filter_clip(int16_t *output, int16_t *low, int16_t *high, + int width, int clip) { filter(output, 1, low, 1, high, 1, width, clip); } -static void vert_filter(int16_t *output, int out_stride, int16_t *low, int low_stride, - int16_t *high, int high_stride, int len) +static void vert_filter(int16_t *output, ptrdiff_t out_stride, + int16_t *low, ptrdiff_t low_stride, + int16_t *high, ptrdiff_t high_stride, int len) { filter(output, out_stride, low, low_stride, high, high_stride, len, 0); } -static void free_buffers(AVCodecContext *avctx) +static void free_buffers(CFHDContext *s) { - CFHDContext *s = avctx->priv_data; int i, j; - for (i = 0; i < 4; i++) { + for (i = 0; i < FF_ARRAY_ELEMS(s->plane); i++) { av_freep(&s->plane[i].idwt_buf); av_freep(&s->plane[i].idwt_tmp); @@ -156,37 +177,43 @@ static void free_buffers(AVCodecContext *avctx) static int alloc_buffers(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; - int i, j, k, ret, planes; + int i, j, ret, planes; + int chroma_x_shift, chroma_y_shift; + unsigned k; if ((ret = ff_set_dimensions(avctx, s->coded_width, s->coded_height)) < 0) return ret; avctx->pix_fmt = s->coded_format; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); - planes = av_pix_fmt_count_planes(avctx->pix_fmt); + if ((ret = av_pix_fmt_get_chroma_sub_sample(s->coded_format, + &chroma_x_shift, + &chroma_y_shift)) < 0) + return ret; + planes = av_pix_fmt_count_planes(s->coded_format); for (i = 0; i < planes; i++) { - int width = i ? avctx->width >> s->chroma_x_shift : avctx->width; - int height = i ? avctx->height >> s->chroma_y_shift : avctx->height; - int stride = FFALIGN(width / 8, 8) * 8; int w8, h8, w4, h4, w2, h2; - height = FFALIGN(height / 8, 2) * 8; - s->plane[i].width = width; + int width = i ? avctx->width >> chroma_x_shift : avctx->width; + int height = i ? avctx->height >> chroma_y_shift : avctx->height; + ptrdiff_t stride = FFALIGN(width / 8, 8) * 8; + height = FFALIGN(height / 8, 2) * 8; + s->plane[i].width = width; s->plane[i].height = height; s->plane[i].stride = stride; - w8 = FFALIGN(s->plane[i].width / 8, 8); + w8 = FFALIGN(s->plane[i].width / 8, 8); h8 = FFALIGN(s->plane[i].height / 8, 2); w4 = w8 * 2; h4 = h8 * 2; w2 = w4 * 2; h2 = h4 * 2; - s->plane[i].idwt_buf = av_mallocz_array(height * stride, sizeof(*s->plane[i].idwt_buf)); - s->plane[i].idwt_tmp = av_malloc_array(height * stride, sizeof(*s->plane[i].idwt_tmp)); - if (!s->plane[i].idwt_buf || !s->plane[i].idwt_tmp) { + s->plane[i].idwt_buf = + av_mallocz_array(height * stride, sizeof(*s->plane[i].idwt_buf)); + s->plane[i].idwt_tmp = + av_malloc_array(height * stride, sizeof(*s->plane[i].idwt_tmp)); + if (!s->plane[i].idwt_buf || !s->plane[i].idwt_tmp) return AVERROR(ENOMEM); - } s->plane[i].subband[0] = s->plane[i].idwt_buf; s->plane[i].subband[1] = s->plane[i].idwt_buf + 2 * w8 * h8; @@ -200,7 +227,7 @@ static int alloc_buffers(AVCodecContext *avctx) s->plane[i].subband[9] = s->plane[i].idwt_buf + 3 * w2 * h2; for (j = 0; j < DWT_LEVELS; j++) { - for(k = 0; k < 4; k++) { + for (k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { s->plane[i].band[j][k].a_width = w8 << j; s->plane[i].band[j][k].a_height = h8 << j; } @@ -209,10 +236,10 @@ static int alloc_buffers(AVCodecContext *avctx) /* ll2 and ll1 commented out because they are done in-place */ s->plane[i].l_h[0] = s->plane[i].idwt_tmp; s->plane[i].l_h[1] = s->plane[i].idwt_tmp + 2 * w8 * h8; - //s->plane[i].l_h[2] = ll2; + // s->plane[i].l_h[2] = ll2; s->plane[i].l_h[3] = s->plane[i].idwt_tmp; s->plane[i].l_h[4] = s->plane[i].idwt_tmp + 2 * w4 * h4; - //s->plane[i].l_h[5] = ll1; + // s->plane[i].l_h[5] = ll1; s->plane[i].l_h[6] = s->plane[i].idwt_tmp; s->plane[i].l_h[7] = s->plane[i].idwt_tmp + 2 * w2 * h2; } @@ -250,10 +277,10 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, uint16_t data = bytestream2_get_be16(&gb); if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data); - } else if (tag == 20) { + } else if (tag == ImageWidth) { av_log(avctx, AV_LOG_DEBUG, "Width %"PRIu16"\n", data); s->coded_width = data; - } else if (tag == 21) { + } else if (tag == ImageHeight) { av_log(avctx, AV_LOG_DEBUG, "Height %"PRIu16"\n", data); s->coded_height = data; } else if (tag == 101) { @@ -264,7 +291,7 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, break; } s->bpc = data; - } else if (tag == 12) { + } else if (tag == ChannelCount) { av_log(avctx, AV_LOG_DEBUG, "Channel Count: %"PRIu16"\n", data); s->channel_cnt = data; if (data > 4) { @@ -272,14 +299,14 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, ret = AVERROR_PATCHWELCOME; break; } - } else if (tag == 14) { + } else if (tag == SubbandCount) { av_log(avctx, AV_LOG_DEBUG, "Subband Count: %"PRIu16"\n", data); if (data != SUBBAND_COUNT) { av_log(avctx, AV_LOG_ERROR, "Subband Count of %"PRIu16" is unsupported\n", data); ret = AVERROR_PATCHWELCOME; break; } - } else if (tag == 62) { + } else if (tag == ChannelNumber) { s->channel_num = data; av_log(avctx, AV_LOG_DEBUG, "Channel number %"PRIu16"\n", data); if (s->channel_num >= planes) { @@ -288,7 +315,7 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, break; } init_plane_defaults(s); - } else if (tag == 48) { + } else if (tag == SubbandNumber) { if (s->subband_num != 0 && data == 1) // hack s->level++; av_log(avctx, AV_LOG_DEBUG, "Subband number %"PRIu16"\n", data); @@ -311,12 +338,12 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, ret = AVERROR(EINVAL); break; } - } else if (tag == 35) + } else if (tag == LowpassPrecision) av_log(avctx, AV_LOG_DEBUG, "Lowpass precision bits: %"PRIu16"\n", data); - else if (tag == 53) { + else if (tag == Quantization) { s->quantisation = data; av_log(avctx, AV_LOG_DEBUG, "Quantisation: %"PRIu16"\n", data); - } else if (tag == 109) { + } else if (tag == PrescaleShift) { s->prescale_shift[0] = (data >> 0) & 0x7; s->prescale_shift[1] = (data >> 3) & 0x7; s->prescale_shift[2] = (data >> 6) & 0x7; @@ -429,6 +456,9 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, break; } planes = av_pix_fmt_count_planes(s->coded_format); + } else if (tag == -85) { + av_log(avctx, AV_LOG_DEBUG, "Cropped height %"PRIu16"\n", data); + s->cropped_height = data; } else av_log(avctx, AV_LOG_DEBUG, "Unknown tag %i data %x\n", tag, data); @@ -437,15 +467,17 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, s->coded_format != AV_PIX_FMT_NONE) { if (s->a_width != s->coded_width || s->a_height != s->coded_height || s->a_format != s->coded_format) { - free_buffers(avctx); + free_buffers(s); if ((ret = alloc_buffers(avctx)) < 0) { - free_buffers(avctx); + free_buffers(s); return ret; } } ret = ff_set_dimensions(avctx, s->coded_width, s->coded_height); if (ret < 0) return ret; + if (s->cropped_height) + avctx->height = s->cropped_height; frame.f->width = frame.f->height = 0; @@ -775,11 +807,11 @@ end: return avpkt->size; } -static av_cold int cfhd_close_decoder(AVCodecContext *avctx) +static av_cold int cfhd_close(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; - free_buffers(avctx); + free_buffers(s); if (!avctx->internal->is_copy) { ff_free_vlc(&s->vlc_9); @@ -790,14 +822,14 @@ static av_cold int cfhd_close_decoder(AVCodecContext *avctx) } AVCodec ff_cfhd_decoder = { - .name = "cfhd", - .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_CFHD, - .priv_data_size = sizeof(CFHDContext), - .init = cfhd_decode_init, - .close = cfhd_close_decoder, - .decode = cfhd_decode, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, - .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .name = "cfhd", + .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_CFHD, + .priv_data_size = sizeof(CFHDContext), + .init = cfhd_init, + .close = cfhd_close, + .decode = cfhd_decode, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 67a0e4c32..2573e750a 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -27,10 +27,10 @@ #include "avcodec.h" #include "get_bits.h" +#include "vlc.h" -#define VLC_BITS 9 -#define NB_VLC_TABLE_9 (71+3) -#define NB_VLC_TABLE_18 (263+1) +#define VLC_BITS 9 +#define SUBBAND_COUNT 10 typedef struct CFHD_RL_VLC_ELEM { int16_t level; @@ -43,7 +43,7 @@ typedef struct CFHD_RL_VLC_ELEM { typedef struct SubBand { int level; int orientation; - int stride; + ptrdiff_t stride; int a_width; int width; int a_height; @@ -62,7 +62,7 @@ typedef struct Plane { int16_t *idwt_tmp; /* TODO: merge this into SubBand structure */ - int16_t *subband[10]; + int16_t *subband[SUBBAND_COUNT]; int16_t *l_h[8]; SubBand band[DWT_LEVELS][4]; @@ -79,18 +79,16 @@ typedef struct CFHDContext { GetBitContext gb; - int chroma_x_shift; - int chroma_y_shift; - int coded_width; int coded_height; - int coded_format; + int cropped_height; + enum AVPixelFormat coded_format; int a_width; int a_height; int a_format; - int bpc; + int bpc; // bits per channel/component int channel_cnt; int subband_cnt; int channel_num; @@ -106,7 +104,6 @@ typedef struct CFHDContext { uint8_t prescale_shift[3]; Plane plane[4]; - } CFHDContext; int ff_cfhd_init_vlcs(CFHDContext *s); diff --git a/libavcodec/cfhddata.c b/libavcodec/cfhddata.c index 9330d3464..5df68d4b3 100644 --- a/libavcodec/cfhddata.c +++ b/libavcodec/cfhddata.c @@ -18,7 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "stdint.h" +#include + +#include "libavutil/attributes.h" + #include "cfhd.h" /* some special codewords, not sure what they all mean */ @@ -29,6 +32,31 @@ #define TABLE_9_BAND_END3 0x38F0B3Eh #define TABLE_9_BAND_END_LEN3 26 +#define NB_VLC_TABLE_9 (71 + 3) +#define NB_VLC_TABLE_18 (263 + 1) + +static const uint32_t table_9_vlc_bits[NB_VLC_TABLE_9] = { + 0, 0x2, 0xc, 0x1a, + 0x1d, 0x1e, 0x39, 0x3e, + 0x37, 0x7e, 0x6c, 0xe2, + 0xfe, 0xdb, 0xe0, 0x1c3, + 0x1c6, 0x1ff, 0x1fe, 0x1b5, + 0x369, 0x385, 0x71d, 0x6d0, + 0x708, 0x71f, 0xe3d, 0xe39, + 0xe13, 0xe12, 0x1c71, 0x1b45, + 0x1b47, 0x3689, 0x38f2, 0x38e1, + 0x38e0, 0x38f1, 0x3688, 0x6d1b, + 0x71e0, 0x6d19, 0x71e7, 0xe3cd, + 0xda35, 0xda30, 0xe3c3, 0x1b469, + 0x1b462, 0x1c798, 0x1b463, 0x1c799, + 0x38f08, 0x38f09, 0x38f0a, 0x6d1a0, + 0x6d1a3, 0x6d1a1, 0xda345, 0xda344, + 0xe3c2d, 0xe3c2f, 0xe3c2e, 0x38f0b2, + 0x71e160, 0x71e162, 0x71e166, 0x71e161, + 0xe3c2ce, 0xe3c2c6, 0xe3c2c7, 0x1C7859E, + 0x38F0B3F, 0x38F0B3E, +}; + static const uint8_t table_9_vlc_len[NB_VLC_TABLE_9] = { 1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, @@ -42,19 +70,6 @@ static const uint8_t table_9_vlc_len[NB_VLC_TABLE_9] = { 26, 26, }; -static const uint32_t table_9_vlc_bits[NB_VLC_TABLE_9] = { - 0, 0x2, 0xc, 0x1a, 0x1d, 0x1e, 0x39, 0x3e, - 0x37, 0x7e, 0x6c, 0xe2, 0xfe, 0xdb, 0xe0, 0x1c3, - 0x1c6, 0x1ff, 0x1fe, 0x1b5, 0x369, 0x385, 0x71d, 0x6d0, - 0x708, 0x71f, 0xe3d, 0xe39, 0xe13, 0xe12, 0x1c71, 0x1b45, - 0x1b47, 0x3689, 0x38f2, 0x38e1, 0x38e0, 0x38f1, 0x3688, 0x6d1b, - 0x71e0, 0x6d19, 0x71e7, 0xe3cd, 0xda35, 0xda30, 0xe3c3, 0x1b469, - 0x1b462, 0x1c798, 0x1b463, 0x1c799, 0x38f08, 0x38f09, 0x38f0a, 0x6d1a0, - 0x6d1a3, 0x6d1a1, 0xda345, 0xda344, 0xe3c2d, 0xe3c2f, 0xe3c2e, 0x38f0b2, - 0x71e160, 0x71e162, 0x71e166, 0x71e161, 0xe3c2ce, 0xe3c2c6, 0xe3c2c7, 0x1C7859E, - 0x38F0B3F, 0x38F0B3E, -}; - static const uint16_t table_9_vlc_run[NB_VLC_TABLE_9] = { 1, 1, 1, 1, 12, 1, 32, 160, 1, 1, 1, 320, 1, 1, 80, 120, @@ -82,39 +97,72 @@ static const uint8_t table_9_vlc_level[NB_VLC_TABLE_9] = { }; static const uint32_t table_18_vlc_bits[NB_VLC_TABLE_18] = { - 0, 0x2, 0x7, 0x19, 0x30, 0x36, 0x6f, 0x63, - 0x69, 0x6b, 0xd1, 0xd4, 0xdc, 0x189, 0x18a, 0x1a0, - 0x1ab, 0x377, 0x310, 0x316, 0x343, 0x354, 0x375, 0x623, - 0x684, 0x685, 0x6ab, 0x6ec, 0xddb, 0xc5c, 0xc5e, 0xc44, - 0xd55, 0xdd1, 0xdd3, 0x1bb5, 0x188b, 0x18bb, 0x18bf, 0x1aa8, - 0x1ba0, 0x1ba5, 0x1ba4, 0x3115, 0x3175, 0x317d, 0x3553, 0x3768, - 0x6e87, 0x6ed3, 0x62e8, 0x62f8, 0x6228, 0x6aa4, 0x6e85, 0xc453, - 0xc5d3, 0xc5f3, 0xdda4, 0xdd08, 0xdd0c, 0x1bb4b, 0x1bb4a, 0x18ba5, - 0x18be5, 0x1aa95, 0x1aa97, 0x188a4, 0x1ba13, 0x31748, 0x317c8, 0x35528, - 0x3552c, 0x37424, 0x37434, 0x37436, 0x62294, 0x62e92, 0x62f92, 0x6aa52, - 0x6aa5a, 0x6e86a, 0x6e86e, 0x6e84a, 0xc452a, 0xc5d27, 0xc5f26, 0xd54a6, - 0xd54b6, 0xdd096, 0xdd0d6, 0xdd0de, 0x188a56, 0x18ba4d, 0x18be4e, 0x18be4f, - 0x1aa96e, 0x1ba12e, 0x1ba12f, 0x1ba1af, 0x1ba1bf, 0x37435d, 0x37437d, 0x317498, - 0x35529c, 0x35529d, 0x3552de, 0x3552df, 0x62e933, 0x62295d, 0x6aa53d, 0x6aa53f, - 0x6aa53e, 0x6e86b9, 0x6e86f8, 0xd54a79, 0xc5d265, 0xc452b8, 0xdd0d71, 0xd54a78, - 0xdd0d70, 0xdd0df2, 0xdd0df3, 0x188a5f6, 0x188a5f5, 0x188a5f4, 0x188a5f3, 0x188a5f2, - 0x188a5f1, 0x188a5f0, 0x188a5ef, 0x188a5ee, 0x188a5ed, 0x188a5aa, 0x188a5e3, 0x188a5df, - 0x188a589, 0x188a5dd, 0x188a578, 0x188a5e0, 0x188a588, 0x188a5d6, 0x188a5db, 0x188a5e1, - 0x188a587, 0x188a59a, 0x188a5c4, 0x188a5ec, 0x188a586, 0x188a573, 0x188a59c, 0x188a5c8, - 0x188a5fb, 0x188a5a1, 0x188a5eb, 0x188a5a8, 0x188a584, 0x188a5d2, 0x188a599, 0x188a598, - 0x188a583, 0x18ba4c9, 0x188a5d0, 0x188a594, 0x188a582, 0x188a5cb, 0x188a5d8, 0x188a5e7, - 0x188a581, 0x188a5ea, 0x188a5a9, 0x188a5a6, 0x188a580, 0x188a5a0, 0x188a59d, 0x188a5c3, - 0x188a57f, 0x188a5c0, 0x188a5de, 0x188a5d4, 0x188a57e, 0x188a5c2, 0x188a592, 0x188a5cd, - 0x188a57d, 0x188a5a3, 0x188a5e8, 0x188a5a2, 0x188a57c, 0x188a58e, 0x188a5b3, 0x188a5b2, - 0x188a5b1, 0x188a5b0, 0x188a5af, 0x188a5ae, 0x188a5ad, 0x188a5ac, 0x188a5ab, 0x188a5da, - 0x188a5e4, 0x188a5e5, 0x188a5d9, 0x188a5b5, 0x188a5bc, 0x188a5bd, 0x188a5e9, 0x188a5cc, - 0x188a585, 0x188a5d3, 0x188a5e2, 0x188a595, 0x188a596, 0x188a5b8, 0x188a590, 0x188a5c9, - 0x188a5a4, 0x188a5e6, 0x188a5a5, 0x188a5ce, 0x188a5bf, 0x188a572, 0x188a59b, 0x188a5be, - 0x188a5c7, 0x188a5ca, 0x188a5d5, 0x188a57b, 0x188a58d, 0x188a58c, 0x188a58b, 0x188a58a, - 0x18ba4c8, 0x188a5c5, 0x188a5fa, 0x188a5bb, 0x188a5c1, 0x188a5cf, 0x188a5b9, 0x188a5b6, - 0x188a597, 0x188a5fe, 0x188a5d7, 0x188a5ba, 0x188a591, 0x188a5c6, 0x188a5dc, 0x188a57a, - 0x188a59f, 0x188a5f9, 0x188a5b4, 0x188a5a7, 0x188a58f, 0x188a5fd, 0x188a5b7, 0x188a593, - 0x188a59e, 0x188a5f8, 0x188a5ff, 0x188a5fc, 0x188a579, 0x188a5f7, 0x3114ba2, 0x3114ba3, + 0, 0x2, 0x7, 0x19, + 0x30, 0x36, 0x6f, 0x63, + 0x69, 0x6b, 0xd1, 0xd4, + 0xdc, 0x189, 0x18a, 0x1a0, + 0x1ab, 0x377, 0x310, 0x316, + 0x343, 0x354, 0x375, 0x623, + 0x684, 0x685, 0x6ab, 0x6ec, + 0xddb, 0xc5c, 0xc5e, 0xc44, + 0xd55, 0xdd1, 0xdd3, 0x1bb5, + 0x188b, 0x18bb, 0x18bf, 0x1aa8, + 0x1ba0, 0x1ba5, 0x1ba4, 0x3115, + 0x3175, 0x317d, 0x3553, 0x3768, + 0x6e87, 0x6ed3, 0x62e8, 0x62f8, + 0x6228, 0x6aa4, 0x6e85, 0xc453, + 0xc5d3, 0xc5f3, 0xdda4, 0xdd08, + 0xdd0c, 0x1bb4b, 0x1bb4a, 0x18ba5, + 0x18be5, 0x1aa95, 0x1aa97, 0x188a4, + 0x1ba13, 0x31748, 0x317c8, 0x35528, + 0x3552c, 0x37424, 0x37434, 0x37436, + 0x62294, 0x62e92, 0x62f92, 0x6aa52, + 0x6aa5a, 0x6e86a, 0x6e86e, 0x6e84a, + 0xc452a, 0xc5d27, 0xc5f26, 0xd54a6, + 0xd54b6, 0xdd096, 0xdd0d6, 0xdd0de, + 0x188a56, 0x18ba4d, 0x18be4e, 0x18be4f, + 0x1aa96e, 0x1ba12e, 0x1ba12f, 0x1ba1af, + 0x1ba1bf, 0x37435d, 0x37437d, 0x317498, + 0x35529c, 0x35529d, 0x3552de, 0x3552df, + 0x62e933, 0x62295d, 0x6aa53d, 0x6aa53f, + 0x6aa53e, 0x6e86b9, 0x6e86f8, 0xd54a79, + 0xc5d265, 0xc452b8, 0xdd0d71, 0xd54a78, + 0xdd0d70, 0xdd0df2, 0xdd0df3, 0x188a5f6, + 0x188a5f5, 0x188a5f4, 0x188a5f3, 0x188a5f2, + 0x188a5f1, 0x188a5f0, 0x188a5ef, 0x188a5ee, + 0x188a5ed, 0x188a5aa, 0x188a5e3, 0x188a5df, + 0x188a589, 0x188a5dd, 0x188a578, 0x188a5e0, + 0x188a588, 0x188a5d6, 0x188a5db, 0x188a5e1, + 0x188a587, 0x188a59a, 0x188a5c4, 0x188a5ec, + 0x188a586, 0x188a573, 0x188a59c, 0x188a5c8, + 0x188a5fb, 0x188a5a1, 0x188a5eb, 0x188a5a8, + 0x188a584, 0x188a5d2, 0x188a599, 0x188a598, + 0x188a583, 0x18ba4c9, 0x188a5d0, 0x188a594, + 0x188a582, 0x188a5cb, 0x188a5d8, 0x188a5e7, + 0x188a581, 0x188a5ea, 0x188a5a9, 0x188a5a6, + 0x188a580, 0x188a5a0, 0x188a59d, 0x188a5c3, + 0x188a57f, 0x188a5c0, 0x188a5de, 0x188a5d4, + 0x188a57e, 0x188a5c2, 0x188a592, 0x188a5cd, + 0x188a57d, 0x188a5a3, 0x188a5e8, 0x188a5a2, + 0x188a57c, 0x188a58e, 0x188a5b3, 0x188a5b2, + 0x188a5b1, 0x188a5b0, 0x188a5af, 0x188a5ae, + 0x188a5ad, 0x188a5ac, 0x188a5ab, 0x188a5da, + 0x188a5e4, 0x188a5e5, 0x188a5d9, 0x188a5b5, + 0x188a5bc, 0x188a5bd, 0x188a5e9, 0x188a5cc, + 0x188a585, 0x188a5d3, 0x188a5e2, 0x188a595, + 0x188a596, 0x188a5b8, 0x188a590, 0x188a5c9, + 0x188a5a4, 0x188a5e6, 0x188a5a5, 0x188a5ce, + 0x188a5bf, 0x188a572, 0x188a59b, 0x188a5be, + 0x188a5c7, 0x188a5ca, 0x188a5d5, 0x188a57b, + 0x188a58d, 0x188a58c, 0x188a58b, 0x188a58a, + 0x18ba4c8, 0x188a5c5, 0x188a5fa, 0x188a5bb, + 0x188a5c1, 0x188a5cf, 0x188a5b9, 0x188a5b6, + 0x188a597, 0x188a5fe, 0x188a5d7, 0x188a5ba, + 0x188a591, 0x188a5c6, 0x188a5dc, 0x188a57a, + 0x188a59f, 0x188a5f9, 0x188a5b4, 0x188a5a7, + 0x188a58f, 0x188a5fd, 0x188a5b7, 0x188a593, + 0x188a59e, 0x188a5f8, 0x188a5ff, 0x188a5fc, + 0x188a579, 0x188a5f7, 0x3114ba2, 0x3114ba3, }; static const uint8_t table_18_vlc_len[NB_VLC_TABLE_18] = { @@ -154,39 +202,39 @@ static const uint8_t table_18_vlc_len[NB_VLC_TABLE_18] = { }; static const uint16_t table_18_vlc_run[NB_VLC_TABLE_18] = { - 1, 1, 1, 1, 1, 1, 1, 1, - 12, 1, 20, 1, 1, 1, 32, 1, - 1, 1, 1, 1, 60, 1, 1, 1, - 1, 100, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 180, 1, - 1, 320, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 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, + 1, 1, 1, 1, 1, 1, 1, 1, + 12, 1, 20, 1, 1, 1, 32, 1, + 1, 1, 1, 1, 60, 1, 1, 1, + 1, 100, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 180, 1, + 1, 320, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 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, }; static const uint8_t table_18_vlc_level[NB_VLC_TABLE_18] = { diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c index a28f66907..93917fafe 100644 --- a/libavcodec/cinepakenc.c +++ b/libavcodec/cinepakenc.c @@ -4,90 +4,61 @@ * * Fixes and improvements, vintage decoders compatibility * (c) 2013, 2014 Rl, Aetey Global Technologies AB + * + * 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. + */ -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. - +/* + * TODO: + * - optimize: color space conversion (move conversion to libswscale), ... * MAYBE: * - "optimally" split the frame into several non-regular areas * using a separate codebook pair for each area and approximating * the area by several rectangular strips (generally not full width ones) * (use quadtree splitting? a simple fixed-granularity grid?) - * - * - * version 2014-01-23 Rl - * - added option handling for flexibility - * - * version 2014-01-21 Rl - * - believe it or not, now we get even smaller files, with better quality - * (which means I missed an optimization earlier :) - * - * version 2014-01-20 Rl - * - made the encoder compatible with vintage decoders - * and added some yet unused code for possible future - * incremental codebook updates - * - fixed a small memory leak - * - * version 2013-04-28 Rl - * - bugfixed codebook optimization logic - * - * version 2013-02-14 Rl - * "Valentine's Day" version: - * - made strip division more robust - * - minimized bruteforcing the number of strips, - * (costs some R/D but speeds up compession a lot), the heuristic - * assumption is that score as a function of the number of strips has - * one wide minimum which moves slowly, of course not fully true - * - simplified codebook generation, - * the old code was meant for other optimizations than we actually do - * - optimized the codebook generation / error estimation for MODE_MC - * - * version 2013-02-12 Rl - * - separated codebook training sets, avoided the transfer of wasted bytes, - * which yields both better quality and smaller files - * - now using the correct colorspace (TODO: move conversion to libswscale) - * - * version 2013-02-08 Rl - * - fixes/optimization in multistrip encoding and codebook size choice, - * quality/bitrate is now better than that of the binary proprietary encoder */ -#include "libavutil/intreadwrite.h" -#include "avcodec.h" -#include "libavutil/lfg.h" -#include "elbg.h" -#include "internal.h" +#include #include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/lfg.h" #include "libavutil/opt.h" +#include "avcodec.h" +#include "elbg.h" +#include "internal.h" + #define CVID_HEADER_SIZE 10 #define STRIP_HEADER_SIZE 12 #define CHUNK_HEADER_SIZE 4 #define MB_SIZE 4 //4x4 MBs -#define MB_AREA (MB_SIZE*MB_SIZE) +#define MB_AREA (MB_SIZE * MB_SIZE) -#define VECTOR_MAX 6 //six or four entries per vector depending on format -#define CODEBOOK_MAX 256 //size of a codebook +#define VECTOR_MAX 6 // six or four entries per vector depending on format +#define CODEBOOK_MAX 256 // size of a codebook -#define MAX_STRIPS 32 //Note: having fewer choices regarding the number of strips speeds up encoding (obviously) -#define MIN_STRIPS 1 //Note: having more strips speeds up encoding the frame (this is less obvious) +#define MAX_STRIPS 32 // Note: having fewer choices regarding the number of strips speeds up encoding (obviously) +#define MIN_STRIPS 1 // Note: having more strips speeds up encoding the frame (this is less obvious) // MAX_STRIPS limits the maximum quality you can reach // when you want high quality on high resolutions, // MIN_STRIPS limits the minimum efficiently encodable bit rate @@ -97,7 +68,7 @@ OTHER DEALINGS IN THE SOFTWARE. // NOTE the decoder in ffmpeg has its own arbitrary limitation on the number // of strips, currently 32 -typedef enum { +typedef enum CinepakMode { MODE_V1_ONLY = 0, MODE_V1_V4, MODE_MC, @@ -105,7 +76,7 @@ typedef enum { MODE_COUNT, } CinepakMode; -typedef enum { +typedef enum mb_encoding { ENC_V1, ENC_V4, ENC_SKIP, @@ -113,24 +84,24 @@ typedef enum { ENC_UNCERTAIN } mb_encoding; -typedef struct { - int v1_vector; //index into v1 codebook - int v1_error; //error when using V1 encoding - int v4_vector[4]; //indices into v4 codebook - int v4_error; //error when using V4 encoding - int skip_error; //error when block is skipped (aka copied from last frame) - mb_encoding best_encoding; //last result from calculate_mode_score() +typedef struct mb_info { + int v1_vector; // index into v1 codebook + int v1_error; // error when using V1 encoding + int v4_vector[4]; // indices into v4 codebook + int v4_error; // error when using V4 encoding + int skip_error; // error when block is skipped (aka copied from last frame) + mb_encoding best_encoding; // last result from calculate_mode_score() } mb_info; -typedef struct { - int v1_codebook[CODEBOOK_MAX*VECTOR_MAX]; - int v4_codebook[CODEBOOK_MAX*VECTOR_MAX]; +typedef struct strip_info { + int v1_codebook[CODEBOOK_MAX * VECTOR_MAX]; + int v4_codebook[CODEBOOK_MAX * VECTOR_MAX]; int v1_size; int v4_size; CinepakMode mode; } strip_info; -typedef struct { +typedef struct CinepakEncContext { const AVClass *class; AVCodecContext *avctx; unsigned char *pict_bufs[4], *strip_buf, *frame_buf; @@ -146,15 +117,10 @@ typedef struct { uint64_t lambda; int *codebook_input; int *codebook_closest; - mb_info *mb; //MB RD state - int min_strips; //the current limit - int max_strips; //the current limit -#ifdef CINEPAKENC_DEBUG - mb_info *best_mb; //TODO: remove. only used for printing stats - int num_v1_mode, num_v4_mode, num_mc_mode; - int num_v1_encs, num_v4_encs, num_skips; -#endif -// options + mb_info *mb; // MB RD state + int min_strips; // the current limit + int max_strips; // the current limit + // options int max_extra_cb_iterations; int skip_empty_cb; int min_min_strips; @@ -165,11 +131,16 @@ typedef struct { #define OFFSET(x) offsetof(CinepakEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "max_extra_cb_iterations", "Max extra codebook recalculation passes, more is better and slower", OFFSET(max_extra_cb_iterations), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, VE }, - { "skip_empty_cb", "Avoid wasting bytes, ignore vintage MacOS decoder", OFFSET(skip_empty_cb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "max_strips", "Limit strips/frame, vintage compatible is 1..3, otherwise the more the better", OFFSET(max_max_strips), AV_OPT_TYPE_INT, { .i64 = 3 }, MIN_STRIPS, MAX_STRIPS, VE }, - { "min_strips", "Enforce min strips/frame, more is worse and faster, must be <= max_strips", OFFSET(min_min_strips), AV_OPT_TYPE_INT, { .i64 = MIN_STRIPS }, MIN_STRIPS, MAX_STRIPS, VE }, - { "strip_number_adaptivity", "How fast the strip number adapts, more is slightly better, much slower", OFFSET(strip_number_delta_range), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_STRIPS-MIN_STRIPS, VE }, + { "max_extra_cb_iterations", "Max extra codebook recalculation passes, more is better and slower", + OFFSET(max_extra_cb_iterations), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, VE }, + { "skip_empty_cb", "Avoid wasting bytes, ignore vintage MacOS decoder", + OFFSET(skip_empty_cb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "max_strips", "Limit strips/frame, vintage compatible is 1..3, otherwise the more the better", + OFFSET(max_max_strips), AV_OPT_TYPE_INT, { .i64 = 3 }, MIN_STRIPS, MAX_STRIPS, VE }, + { "min_strips", "Enforce min strips/frame, more is worse and faster, must be <= max_strips", + OFFSET(min_min_strips), AV_OPT_TYPE_INT, { .i64 = MIN_STRIPS }, MIN_STRIPS, MAX_STRIPS, VE }, + { "strip_number_adaptivity", "How fast the strip number adapts, more is slightly better, much slower", + OFFSET(strip_number_delta_range), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_STRIPS - MIN_STRIPS, VE }, { NULL }, }; @@ -187,13 +158,13 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) if (avctx->width & 3 || avctx->height & 3) { av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of four (got %ix%i)\n", - avctx->width, avctx->height); + avctx->width, avctx->height); return AVERROR(EINVAL); } if (s->min_min_strips > s->max_max_strips) { - av_log(avctx, AV_LOG_ERROR, "minimal number of strips can not exceed maximal (got %i and %i)\n", - s->min_min_strips, s->max_max_strips); + av_log(avctx, AV_LOG_ERROR, "minimum number of strips must not exceed maximum (got %i and %i)\n", + s->min_min_strips, s->max_max_strips); return AVERROR(EINVAL); } @@ -207,23 +178,23 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) if (!(s->input_frame = av_frame_alloc())) goto enomem; - if (!(s->codebook_input = av_malloc(sizeof(int) * (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2))) + if (!(s->codebook_input = av_malloc_array((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2, sizeof(*s->codebook_input)))) goto enomem; - if (!(s->codebook_closest = av_malloc(sizeof(int) * (avctx->width * avctx->height) >> 2))) + if (!(s->codebook_closest = av_malloc_array((avctx->width * avctx->height) >> 2, sizeof(*s->codebook_closest)))) goto enomem; - for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) - if(!(s->pict_bufs[x] = av_malloc((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2))) + for (x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) + if (!(s->pict_bufs[x] = av_malloc((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2))) goto enomem; mb_count = avctx->width * avctx->height / MB_AREA; - //the largest possible chunk is 0x31 with all MBs encoded in V4 mode - //and full codebooks being replaced in INTER mode, + // the largest possible chunk is 0x31 with all MBs encoded in V4 mode + // and full codebooks being replaced in INTER mode, // which is 34 bits per MB - //and 2*256 extra flag bits per strip - strip_buf_size = STRIP_HEADER_SIZE + 3 * CHUNK_HEADER_SIZE + 2 * VECTOR_MAX * CODEBOOK_MAX + 4 * (mb_count + (mb_count + 15) / 16) + (2 * CODEBOOK_MAX)/8; + // and 2*256 extra flag bits per strip + strip_buf_size = STRIP_HEADER_SIZE + 3 * CHUNK_HEADER_SIZE + 2 * VECTOR_MAX * CODEBOOK_MAX + 4 * (mb_count + (mb_count + 15) / 16) + (2 * CODEBOOK_MAX) / 8; frame_buf_size = CVID_HEADER_SIZE + s->max_max_strips * strip_buf_size; @@ -236,21 +207,16 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) if (!(s->mb = av_malloc_array(mb_count, sizeof(mb_info)))) goto enomem; -#ifdef CINEPAKENC_DEBUG - if (!(s->best_mb = av_malloc_array(mb_count, sizeof(mb_info)))) - goto enomem; -#endif - av_lfg_init(&s->randctx, 1); - s->avctx = avctx; - s->w = avctx->width; - s->h = avctx->height; + s->avctx = avctx; + s->w = avctx->width; + s->h = avctx->height; s->frame_buf_size = frame_buf_size; - s->curframe = 0; - s->keyint = avctx->keyint_min; - s->pix_fmt = avctx->pix_fmt; + s->curframe = 0; + s->keyint = avctx->keyint_min; + s->pix_fmt = avctx->pix_fmt; - //set up AVFrames + // set up AVFrames s->last_frame->data[0] = s->pict_bufs[0]; s->last_frame->linesize[0] = s->w; s->best_frame->data[0] = s->pict_bufs[1]; @@ -259,32 +225,32 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) s->scratch_frame->linesize[0] = s->w; if (s->pix_fmt == AV_PIX_FMT_RGB24) { - s->last_frame->data[1] = s->last_frame->data[0] + s->w * s->h; - s->last_frame->data[2] = s->last_frame->data[1] + ((s->w * s->h) >> 2); - s->last_frame->linesize[1] = s->last_frame->linesize[2] = s->w >> 1; + s->last_frame->data[1] = s->last_frame->data[0] + s->w * s->h; + s->last_frame->data[2] = s->last_frame->data[1] + ((s->w * s->h) >> 2); + s->last_frame->linesize[1] = + s->last_frame->linesize[2] = s->w >> 1; - s->best_frame->data[1] = s->best_frame->data[0] + s->w * s->h; - s->best_frame->data[2] = s->best_frame->data[1] + ((s->w * s->h) >> 2); - s->best_frame->linesize[1] = s->best_frame->linesize[2] = s->w >> 1; + s->best_frame->data[1] = s->best_frame->data[0] + s->w * s->h; + s->best_frame->data[2] = s->best_frame->data[1] + ((s->w * s->h) >> 2); + s->best_frame->linesize[1] = + s->best_frame->linesize[2] = s->w >> 1; - s->scratch_frame->data[1] = s->scratch_frame->data[0] + s->w * s->h; + s->scratch_frame->data[1] = s->scratch_frame->data[0] + s->w * s->h; s->scratch_frame->data[2] = s->scratch_frame->data[1] + ((s->w * s->h) >> 2); - s->scratch_frame->linesize[1] = s->scratch_frame->linesize[2] = s->w >> 1; + s->scratch_frame->linesize[1] = + s->scratch_frame->linesize[2] = s->w >> 1; - s->input_frame->data[0] = s->pict_bufs[3]; - s->input_frame->linesize[0] = s->w; - s->input_frame->data[1] = s->input_frame->data[0] + s->w * s->h; - s->input_frame->data[2] = s->input_frame->data[1] + ((s->w * s->h) >> 2); - s->input_frame->linesize[1] = s->input_frame->linesize[2] = s->w >> 1; + s->input_frame->data[0] = s->pict_bufs[3]; + s->input_frame->linesize[0] = s->w; + s->input_frame->data[1] = s->input_frame->data[0] + s->w * s->h; + s->input_frame->data[2] = s->input_frame->data[1] + ((s->w * s->h) >> 2); + s->input_frame->linesize[1] = + s->input_frame->linesize[2] = s->w >> 1; } s->min_strips = s->min_min_strips; s->max_strips = s->max_max_strips; -#ifdef CINEPAKENC_DEBUG - s->num_v1_mode = s->num_v4_mode = s->num_mc_mode = s->num_v1_encs = s->num_v4_encs = s->num_skips = 0; -#endif - return 0; enomem: @@ -298,90 +264,68 @@ enomem: av_freep(&s->strip_buf); av_freep(&s->frame_buf); av_freep(&s->mb); -#ifdef CINEPAKENC_DEBUG - av_freep(&s->best_mb); -#endif - for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) + for (x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) av_freep(&s->pict_bufs[x]); return AVERROR(ENOMEM); } -static int64_t calculate_mode_score(CinepakEncContext *s, int h, strip_info *info, int report, int *training_set_v1_shrunk, int *training_set_v4_shrunk -#ifdef CINEPAK_REPORT_SERR -, int64_t *serr -#endif -) +static int64_t calculate_mode_score(CinepakEncContext *s, int h, + strip_info *info, int report, + int *training_set_v1_shrunk, + int *training_set_v4_shrunk) { - //score = FF_LAMBDA_SCALE * error + lambda * bits + // score = FF_LAMBDA_SCALE * error + lambda * bits int x; int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; - int mb_count = s->w * h / MB_AREA; + int mb_count = s->w * h / MB_AREA; mb_info *mb; int64_t score1, score2, score3; int64_t ret = s->lambda * ((info->v1_size ? CHUNK_HEADER_SIZE + info->v1_size * entry_size : 0) + - (info->v4_size ? CHUNK_HEADER_SIZE + info->v4_size * entry_size : 0) + - CHUNK_HEADER_SIZE) << 3; + (info->v4_size ? CHUNK_HEADER_SIZE + info->v4_size * entry_size : 0) + + CHUNK_HEADER_SIZE) << 3; - //av_log(s->avctx, AV_LOG_INFO, "sizes %3i %3i -> %9"PRId64" score mb_count %i", info->v1_size, info->v4_size, ret, mb_count); - -#ifdef CINEPAK_REPORT_SERR - *serr = 0; -#endif - - switch(info->mode) { + switch (info->mode) { case MODE_V1_ONLY: - //one byte per MB + // one byte per MB ret += s->lambda * 8 * mb_count; -// while calculating we assume all blocks are ENC_V1 - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; + // while calculating we assume all blocks are ENC_V1 + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; ret += FF_LAMBDA_SCALE * mb->v1_error; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif -// this function is never called for report in MODE_V1_ONLY -// if(!report) + // this function is never called for report in MODE_V1_ONLY + // if (!report) mb->best_encoding = ENC_V1; } break; case MODE_V1_V4: - //9 or 33 bits per MB - if(report) { -// no moves between the corresponding training sets are allowed + // 9 or 33 bits per MB + if (report) { + // no moves between the corresponding training sets are allowed *training_set_v1_shrunk = *training_set_v4_shrunk = 0; - for(x = 0; x < mb_count; x++) { + for (x = 0; x < mb_count; x++) { int mberr; mb = &s->mb[x]; - if(mb->best_encoding == ENC_V1) - score1 = s->lambda * 9 + FF_LAMBDA_SCALE * (mberr=mb->v1_error); + if (mb->best_encoding == ENC_V1) + score1 = s->lambda * 9 + FF_LAMBDA_SCALE * (mberr = mb->v1_error); else - score1 = s->lambda * 33 + FF_LAMBDA_SCALE * (mberr=mb->v4_error); + score1 = s->lambda * 33 + FF_LAMBDA_SCALE * (mberr = mb->v4_error); ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mberr; -#endif } } else { // find best mode per block - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; - score1 = s->lambda * 9 + FF_LAMBDA_SCALE * mb->v1_error; + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; + score1 = s->lambda * 9 + FF_LAMBDA_SCALE * mb->v1_error; score2 = s->lambda * 33 + FF_LAMBDA_SCALE * mb->v4_error; - if(score1 <= score2) { + if (score1 <= score2) { ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif mb->best_encoding = ENC_V1; } else { ret += score2; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v4_error; -#endif mb->best_encoding = ENC_V4; } } @@ -389,75 +333,51 @@ static int64_t calculate_mode_score(CinepakEncContext *s, int h, strip_info *inf break; case MODE_MC: - //1, 10 or 34 bits per MB - if(report) { + // 1, 10 or 34 bits per MB + if (report) { int v1_shrunk = 0, v4_shrunk = 0; - for(x = 0; x < mb_count; x++) { + for (x = 0; x < mb_count; x++) { mb = &s->mb[x]; -// it is OK to move blocks to ENC_SKIP here -// but not to any codebook encoding! - score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; - if(mb->best_encoding == ENC_SKIP) { + // it is OK to move blocks to ENC_SKIP here + // but not to any codebook encoding! + score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; + if (mb->best_encoding == ENC_SKIP) { ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif - } else if(mb->best_encoding == ENC_V1) { - if((score2=s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error) >= score1) { + } else if (mb->best_encoding == ENC_V1) { + if ((score2 = s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error) >= score1) { mb->best_encoding = ENC_SKIP; ++v1_shrunk; ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif } else { ret += score2; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif } } else { - if((score3=s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error) >= score1) { + if ((score3 = s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error) >= score1) { mb->best_encoding = ENC_SKIP; ++v4_shrunk; ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif } else { ret += score3; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v4_error; -#endif } } } *training_set_v1_shrunk = v1_shrunk; *training_set_v4_shrunk = v4_shrunk; } else { // find best mode per block - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; - score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; + score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; score2 = s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error; score3 = s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error; - if(score1 <= score2 && score1 <= score3) { + if (score1 <= score2 && score1 <= score3) { ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif mb->best_encoding = ENC_SKIP; - } else if(score2 <= score3) { + } else if (score2 <= score3) { ret += score2; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif mb->best_encoding = ENC_V1; } else { ret += score3; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v4_error; -#endif mb->best_encoding = ENC_V4; } } @@ -476,123 +396,125 @@ static int write_chunk_header(unsigned char *buf, int chunk_type, int chunk_size return CHUNK_HEADER_SIZE; } -static int encode_codebook(CinepakEncContext *s, int *codebook, int size, int chunk_type_yuv, int chunk_type_gray, unsigned char *buf) +static int encode_codebook(CinepakEncContext *s, int *codebook, int size, + int chunk_type_yuv, int chunk_type_gray, + unsigned char *buf) { int x, y, ret, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; int incremental_codebook_replacement_mode = 0; // hardcoded here, - // the compiler should notice that this is a constant -- rl + // the compiler should notice that this is a constant -- rl ret = write_chunk_header(buf, - s->pix_fmt == AV_PIX_FMT_RGB24 ? - chunk_type_yuv+(incremental_codebook_replacement_mode?1:0) : - chunk_type_gray+(incremental_codebook_replacement_mode?1:0), - entry_size * size - + (incremental_codebook_replacement_mode?(size+31)/32*4:0) ); + s->pix_fmt == AV_PIX_FMT_RGB24 ? + chunk_type_yuv + (incremental_codebook_replacement_mode ? 1 : 0) : + chunk_type_gray + (incremental_codebook_replacement_mode ? 1 : 0), + entry_size * size + + (incremental_codebook_replacement_mode ? (size + 31) / 32 * 4 : 0)); -// we do codebook encoding according to the "intra" mode -// but we keep the "dead" code for reference in case we will want -// to use incremental codebook updates (which actually would give us -// "kind of" motion compensation, especially in 1 strip/frame case) -- rl -// (of course, the code will be not useful as-is) - if(incremental_codebook_replacement_mode) { + // we do codebook encoding according to the "intra" mode + // but we keep the "dead" code for reference in case we will want + // to use incremental codebook updates (which actually would give us + // "kind of" motion compensation, especially in 1 strip/frame case) -- rl + // (of course, the code will be not useful as-is) + if (incremental_codebook_replacement_mode) { int flags = 0; int flagsind; - for(x = 0; x < size; x++) { - if(flags == 0) { + for (x = 0; x < size; x++) { + if (flags == 0) { flagsind = ret; - ret += 4; - flags = 0x80000000; + ret += 4; + flags = 0x80000000; } else - flags = ((flags>>1) | 0x80000000); - for(y = 0; y < entry_size; y++) - buf[ret++] = codebook[y + x*entry_size] ^ (y >= 4 ? 0x80 : 0); - if((flags&0xffffffff) == 0xffffffff) { + flags = ((flags >> 1) | 0x80000000); + for (y = 0; y < entry_size; y++) + buf[ret++] = codebook[y + x * entry_size] ^ (y >= 4 ? 0x80 : 0); + if ((flags & 0xffffffff) == 0xffffffff) { AV_WB32(&buf[flagsind], flags); flags = 0; } } - if(flags) + if (flags) AV_WB32(&buf[flagsind], flags); } else - for(x = 0; x < size; x++) - for(y = 0; y < entry_size; y++) - buf[ret++] = codebook[y + x*entry_size] ^ (y >= 4 ? 0x80 : 0); + for (x = 0; x < size; x++) + for (y = 0; y < entry_size; y++) + buf[ret++] = codebook[y + x * entry_size] ^ (y >= 4 ? 0x80 : 0); return ret; } -//sets out to the sub picture starting at (x,y) in in +// sets out to the sub picture starting at (x,y) in in static void get_sub_picture(CinepakEncContext *s, int x, int y, uint8_t * in_data[4], int in_linesize[4], uint8_t *out_data[4], int out_linesize[4]) { - out_data[0] = in_data[0] + x + y * in_linesize[0]; + out_data[0] = in_data[0] + x + y * in_linesize[0]; out_linesize[0] = in_linesize[0]; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - out_data[1] = in_data[1] + (x >> 1) + (y >> 1) * in_linesize[1]; + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + out_data[1] = in_data[1] + (x >> 1) + (y >> 1) * in_linesize[1]; out_linesize[1] = in_linesize[1]; - out_data[2] = in_data[2] + (x >> 1) + (y >> 1) * in_linesize[2]; + out_data[2] = in_data[2] + (x >> 1) + (y >> 1) * in_linesize[2]; out_linesize[2] = in_linesize[2]; } } -//decodes the V1 vector in mb into the 4x4 MB pointed to by data +// decodes the V1 vector in mb into the 4x4 MB pointed to by data static void decode_v1_vector(CinepakEncContext *s, uint8_t *data[4], int linesize[4], int v1_vector, strip_info *info) { int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; data[0][0] = - data[0][1] = - data[0][ linesize[0]] = - data[0][1+ linesize[0]] = info->v1_codebook[v1_vector*entry_size]; + data[0][1] = + data[0][ linesize[0]] = + data[0][1 + linesize[0]] = info->v1_codebook[v1_vector * entry_size]; data[0][2] = - data[0][3] = - data[0][2+ linesize[0]] = - data[0][3+ linesize[0]] = info->v1_codebook[v1_vector*entry_size+1]; + data[0][3] = + data[0][2 + linesize[0]] = + data[0][3 + linesize[0]] = info->v1_codebook[v1_vector * entry_size + 1]; - data[0][2*linesize[0]] = - data[0][1+2*linesize[0]] = - data[0][ 3*linesize[0]] = - data[0][1+3*linesize[0]] = info->v1_codebook[v1_vector*entry_size+2]; + data[0][ 2 * linesize[0]] = + data[0][1 + 2 * linesize[0]] = + data[0][ 3 * linesize[0]] = + data[0][1 + 3 * linesize[0]] = info->v1_codebook[v1_vector * entry_size + 2]; - data[0][2+2*linesize[0]] = - data[0][3+2*linesize[0]] = - data[0][2+3*linesize[0]] = - data[0][3+3*linesize[0]] = info->v1_codebook[v1_vector*entry_size+3]; + data[0][2 + 2 * linesize[0]] = + data[0][3 + 2 * linesize[0]] = + data[0][2 + 3 * linesize[0]] = + data[0][3 + 3 * linesize[0]] = info->v1_codebook[v1_vector * entry_size + 3]; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { + if (s->pix_fmt == AV_PIX_FMT_RGB24) { data[1][0] = - data[1][1] = - data[1][ linesize[1]] = - data[1][1+ linesize[1]] = info->v1_codebook[v1_vector*entry_size+4]; + data[1][1] = + data[1][ linesize[1]] = + data[1][1 + linesize[1]] = info->v1_codebook[v1_vector * entry_size + 4]; data[2][0] = - data[2][1] = - data[2][ linesize[2]] = - data[2][1+ linesize[2]] = info->v1_codebook[v1_vector*entry_size+5]; + data[2][1] = + data[2][ linesize[2]] = + data[2][1 + linesize[2]] = info->v1_codebook[v1_vector * entry_size + 5]; } } -//decodes the V4 vectors in mb into the 4x4 MB pointed to by data +// decodes the V4 vectors in mb into the 4x4 MB pointed to by data static void decode_v4_vector(CinepakEncContext *s, uint8_t *data[4], int linesize[4], int *v4_vector, strip_info *info) { int i, x, y, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; - for(i = y = 0; y < 4; y += 2) { - for(x = 0; x < 4; x += 2, i++) { - data[0][x + y*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size]; - data[0][x+1 + y*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+1]; - data[0][x + (y+1)*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+2]; - data[0][x+1 + (y+1)*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+3]; + for (i = y = 0; y < 4; y += 2) { + for (x = 0; x < 4; x += 2, i++) { + data[0][x + y * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size]; + data[0][x + 1 + y * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size + 1]; + data[0][x + (y + 1) * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size + 2]; + data[0][x + 1 + (y + 1) * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size + 3]; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - data[1][(x>>1) + (y>>1)*linesize[1]] = info->v4_codebook[v4_vector[i]*entry_size+4]; - data[2][(x>>1) + (y>>1)*linesize[2]] = info->v4_codebook[v4_vector[i]*entry_size+5]; + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + data[1][(x >> 1) + (y >> 1) * linesize[1]] = info->v4_codebook[v4_vector[i] * entry_size + 4]; + data[2][(x >> 1) + (y >> 1) * linesize[2]] = info->v4_codebook[v4_vector[i] * entry_size + 5]; } } } @@ -604,19 +526,16 @@ static void copy_mb(CinepakEncContext *s, { int y, p; - for(y = 0; y < MB_SIZE; y++) { - memcpy(a_data[0]+y*a_linesize[0], b_data[0]+y*b_linesize[0], + for (y = 0; y < MB_SIZE; y++) + memcpy(a_data[0] + y * a_linesize[0], b_data[0] + y * b_linesize[0], MB_SIZE); - } - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - for(p = 1; p <= 2; p++) { - for(y = 0; y < MB_SIZE/2; y++) { - memcpy(a_data[p] + y*a_linesize[p], - b_data[p] + y*b_linesize[p], - MB_SIZE/2); - } - } + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + for (p = 1; p <= 2; p++) + for (y = 0; y < MB_SIZE / 2; y++) + memcpy(a_data[p] + y * a_linesize[p], + b_data[p] + y * b_linesize[p], + MB_SIZE / 2); } } @@ -627,74 +546,71 @@ static int encode_mode(CinepakEncContext *s, int h, { int x, y, z, flags, bits, temp_size, header_ofs, ret = 0, mb_count = s->w * h / MB_AREA; int needs_extra_bit, should_write_temp; - unsigned char temp[64]; //32/2 = 16 V4 blocks at 4 B each -> 64 B + unsigned char temp[64]; // 32/2 = 16 V4 blocks at 4 B each -> 64 B mb_info *mb; - uint8_t *sub_scratch_data[4] = {0}, *sub_last_data[4] = {0}; - int sub_scratch_linesize[4] = {0}, sub_last_linesize[4] = {0}; + uint8_t *sub_scratch_data[4] = { 0 }, *sub_last_data[4] = { 0 }; + int sub_scratch_linesize[4] = { 0 }, sub_last_linesize[4] = { 0 }; - //encode codebooks -////// MacOS vintage decoder compatibility dictates the presence of -////// the codebook chunk even when the codebook is empty - pretty dumb... -////// and also the certain order of the codebook chunks -- rl - if(info->v4_size || !s->skip_empty_cb) + // encode codebooks + ////// MacOS vintage decoder compatibility dictates the presence of + ////// the codebook chunk even when the codebook is empty - pretty dumb... + ////// and also the certain order of the codebook chunks -- rl + if (info->v4_size || !s->skip_empty_cb) ret += encode_codebook(s, info->v4_codebook, info->v4_size, 0x20, 0x24, buf + ret); - if(info->v1_size || !s->skip_empty_cb) + if (info->v1_size || !s->skip_empty_cb) ret += encode_codebook(s, info->v1_codebook, info->v1_size, 0x22, 0x26, buf + ret); - //update scratch picture - for(z = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, z++) { + // update scratch picture + for (z = y = 0; y < h; y += MB_SIZE) + for (x = 0; x < s->w; x += MB_SIZE, z++) { mb = &s->mb[z]; get_sub_picture(s, x, y, scratch_data, scratch_linesize, sub_scratch_data, sub_scratch_linesize); - if(info->mode == MODE_MC && mb->best_encoding == ENC_SKIP) { - get_sub_picture(s, x, y, - last_data, last_linesize, + if (info->mode == MODE_MC && mb->best_encoding == ENC_SKIP) { + get_sub_picture(s, x, y, last_data, last_linesize, sub_last_data, sub_last_linesize); copy_mb(s, sub_scratch_data, sub_scratch_linesize, sub_last_data, sub_last_linesize); - } else if(info->mode == MODE_V1_ONLY || mb->best_encoding == ENC_V1) + } else if (info->mode == MODE_V1_ONLY || mb->best_encoding == ENC_V1) decode_v1_vector(s, sub_scratch_data, sub_scratch_linesize, mb->v1_vector, info); else decode_v4_vector(s, sub_scratch_data, sub_scratch_linesize, mb->v4_vector, info); } - } - switch(info->mode) { + switch (info->mode) { case MODE_V1_ONLY: - //av_log(s->avctx, AV_LOG_INFO, "mb_count = %i\n", mb_count); ret += write_chunk_header(buf + ret, 0x32, mb_count); - for(x = 0; x < mb_count; x++) + for (x = 0; x < mb_count; x++) buf[ret++] = s->mb[x].v1_vector; break; case MODE_V1_V4: - //remember header position + // remember header position header_ofs = ret; - ret += CHUNK_HEADER_SIZE; + ret += CHUNK_HEADER_SIZE; - for(x = 0; x < mb_count; x += 32) { + for (x = 0; x < mb_count; x += 32) { flags = 0; - for(y = x; y < FFMIN(x+32, mb_count); y++) - if(s->mb[y].best_encoding == ENC_V4) + for (y = x; y < FFMIN(x + 32, mb_count); y++) + if (s->mb[y].best_encoding == ENC_V4) flags |= 1 << (31 - y + x); AV_WB32(&buf[ret], flags); ret += 4; - for(y = x; y < FFMIN(x+32, mb_count); y++) { + for (y = x; y < FFMIN(x + 32, mb_count); y++) { mb = &s->mb[y]; - if(mb->best_encoding == ENC_V1) + if (mb->best_encoding == ENC_V1) buf[ret++] = mb->v1_vector; else - for(z = 0; z < 4; z++) + for (z = 0; z < 4; z++) buf[ret++] = mb->v4_vector[z]; } } @@ -703,56 +619,56 @@ static int encode_mode(CinepakEncContext *s, int h, break; case MODE_MC: - //remember header position + // remember header position header_ofs = ret; - ret += CHUNK_HEADER_SIZE; - flags = bits = temp_size = 0; + ret += CHUNK_HEADER_SIZE; + flags = bits = temp_size = 0; - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; - flags |= (mb->best_encoding != ENC_SKIP) << (31 - bits++); - needs_extra_bit = 0; + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; + flags |= (mb->best_encoding != ENC_SKIP) << (31 - bits++); + needs_extra_bit = 0; should_write_temp = 0; - if(mb->best_encoding != ENC_SKIP) { - if(bits < 32) + if (mb->best_encoding != ENC_SKIP) { + if (bits < 32) flags |= (mb->best_encoding == ENC_V4) << (31 - bits++); else needs_extra_bit = 1; } - if(bits == 32) { + if (bits == 32) { AV_WB32(&buf[ret], flags); - ret += 4; + ret += 4; flags = bits = 0; - if(mb->best_encoding == ENC_SKIP || needs_extra_bit) { + if (mb->best_encoding == ENC_SKIP || needs_extra_bit) { memcpy(&buf[ret], temp, temp_size); - ret += temp_size; + ret += temp_size; temp_size = 0; } else should_write_temp = 1; } - if(needs_extra_bit) { + if (needs_extra_bit) { flags = (mb->best_encoding == ENC_V4) << 31; - bits = 1; + bits = 1; } - if(mb->best_encoding == ENC_V1) + if (mb->best_encoding == ENC_V1) temp[temp_size++] = mb->v1_vector; - else if(mb->best_encoding == ENC_V4) - for(z = 0; z < 4; z++) + else if (mb->best_encoding == ENC_V4) + for (z = 0; z < 4; z++) temp[temp_size++] = mb->v4_vector[z]; - if(should_write_temp) { + if (should_write_temp) { memcpy(&buf[ret], temp, temp_size); - ret += temp_size; + ret += temp_size; temp_size = 0; } } - if(bits > 0) { + if (bits > 0) { AV_WB32(&buf[ret], flags); ret += 4; memcpy(&buf[ret], temp, temp_size); @@ -767,28 +683,26 @@ static int encode_mode(CinepakEncContext *s, int h, return ret; } -//computes distortion of 4x4 MB in b compared to a +// computes distortion of 4x4 MB in b compared to a static int compute_mb_distortion(CinepakEncContext *s, uint8_t *a_data[4], int a_linesize[4], uint8_t *b_data[4], int b_linesize[4]) { int x, y, p, d, ret = 0; - for(y = 0; y < MB_SIZE; y++) { - for(x = 0; x < MB_SIZE; x++) { - d = a_data[0][x + y*a_linesize[0]] - b_data[0][x + y*b_linesize[0]]; - ret += d*d; + for (y = 0; y < MB_SIZE; y++) + for (x = 0; x < MB_SIZE; x++) { + d = a_data[0][x + y * a_linesize[0]] - b_data[0][x + y * b_linesize[0]]; + ret += d * d; } - } - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - for(p = 1; p <= 2; p++) { - for(y = 0; y < MB_SIZE/2; y++) { - for(x = 0; x < MB_SIZE/2; x++) { - d = a_data[p][x + y*a_linesize[p]] - b_data[p][x + y*b_linesize[p]]; - ret += d*d; + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + for (p = 1; p <= 2; p++) { + for (y = 0; y < MB_SIZE / 2; y++) + for (x = 0; x < MB_SIZE / 2; x++) { + d = a_data[p][x + y * a_linesize[p]] - b_data[p][x + y * b_linesize[p]]; + ret += d * d; } - } } } @@ -796,114 +710,108 @@ static int compute_mb_distortion(CinepakEncContext *s, } // return the possibly adjusted size of the codebook -#define CERTAIN(x) ((x)!=ENC_UNCERTAIN) -static int quantize(CinepakEncContext *s, int h, - uint8_t *data[4], int linesize[4], - int v1mode, strip_info *info, +#define CERTAIN(x) ((x) != ENC_UNCERTAIN) +static int quantize(CinepakEncContext *s, int h, uint8_t *data[4], + int linesize[4], int v1mode, strip_info *info, mb_encoding encoding) { int x, y, i, j, k, x2, y2, x3, y3, plane, shift, mbn; - int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; - int *codebook = v1mode ? info->v1_codebook : info->v4_codebook; - int size = v1mode ? info->v1_size : info->v4_size; + int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; + int *codebook = v1mode ? info->v1_codebook : info->v4_codebook; + int size = v1mode ? info->v1_size : info->v4_size; int64_t total_error = 0; - uint8_t vq_pict_buf[(MB_AREA*3)/2]; - uint8_t *sub_data [4], *vq_data [4]; + uint8_t vq_pict_buf[(MB_AREA * 3) / 2]; + uint8_t *sub_data[4], *vq_data[4]; int sub_linesize[4], vq_linesize[4]; - for(mbn = i = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, ++mbn) { + for (mbn = i = y = 0; y < h; y += MB_SIZE) { + for (x = 0; x < s->w; x += MB_SIZE, ++mbn) { int *base; - if(CERTAIN(encoding)) { -// use for the training only the blocks known to be to be encoded [sic:-] - if(s->mb[mbn].best_encoding != encoding) continue; + if (CERTAIN(encoding)) { + // use for the training only the blocks known to be to be encoded [sic:-] + if (s->mb[mbn].best_encoding != encoding) + continue; } - base = s->codebook_input + i*entry_size; - if(v1mode) { - //subsample - for(j = y2 = 0; y2 < entry_size; y2 += 2) { - for(x2 = 0; x2 < 4; x2 += 2, j++) { - plane = y2 < 4 ? 0 : 1 + (x2 >> 1); - shift = y2 < 4 ? 0 : 1; - x3 = shift ? 0 : x2; - y3 = shift ? 0 : y2; - base[j] = (data[plane][((x+x3) >> shift) + ((y+y3) >> shift) * linesize[plane]] + - data[plane][((x+x3) >> shift) + 1 + ((y+y3) >> shift) * linesize[plane]] + - data[plane][((x+x3) >> shift) + (((y+y3) >> shift) + 1) * linesize[plane]] + - data[plane][((x+x3) >> shift) + 1 + (((y+y3) >> shift) + 1) * linesize[plane]]) >> 2; + base = s->codebook_input + i * entry_size; + if (v1mode) { + // subsample + for (j = y2 = 0; y2 < entry_size; y2 += 2) + for (x2 = 0; x2 < 4; x2 += 2, j++) { + plane = y2 < 4 ? 0 : 1 + (x2 >> 1); + shift = y2 < 4 ? 0 : 1; + x3 = shift ? 0 : x2; + y3 = shift ? 0 : y2; + base[j] = (data[plane][((x + x3) >> shift) + ((y + y3) >> shift) * linesize[plane]] + + data[plane][((x + x3) >> shift) + 1 + ((y + y3) >> shift) * linesize[plane]] + + data[plane][((x + x3) >> shift) + (((y + y3) >> shift) + 1) * linesize[plane]] + + data[plane][((x + x3) >> shift) + 1 + (((y + y3) >> shift) + 1) * linesize[plane]]) >> 2; } - } } else { - //copy - for(j = y2 = 0; y2 < MB_SIZE; y2 += 2) { - for(x2 = 0; x2 < MB_SIZE; x2 += 2) { - for(k = 0; k < entry_size; k++, j++) { + // copy + for (j = y2 = 0; y2 < MB_SIZE; y2 += 2) { + for (x2 = 0; x2 < MB_SIZE; x2 += 2) + for (k = 0; k < entry_size; k++, j++) { plane = k >= 4 ? k - 3 : 0; - if(k >= 4) { - x3 = (x+x2) >> 1; - y3 = (y+y2) >> 1; + if (k >= 4) { + x3 = (x + x2) >> 1; + y3 = (y + y2) >> 1; } else { x3 = x + x2 + (k & 1); y3 = y + y2 + (k >> 1); } - base[j] = data[plane][x3 + y3*linesize[plane]]; + base[j] = data[plane][x3 + y3 * linesize[plane]]; } - } } } i += v1mode ? 1 : 4; } } -// if(i < mbn*(v1mode ? 1 : 4)) { -// av_log(s->avctx, AV_LOG_INFO, "reducing training set for %s from %i to %i (encoding %i)\n", v1mode?"v1":"v4", mbn*(v1mode ? 1 : 4), i, encoding); -// } - if(i == 0) // empty training set, nothing to do + if (i == 0) // empty training set, nothing to do return 0; - if(i < size) { - //av_log(s->avctx, (CERTAIN(encoding) ? AV_LOG_ERROR : AV_LOG_INFO), "WOULD WASTE: %s cbsize %i bigger than training set size %i (encoding %i)\n", v1mode?"v1":"v4", size, i, encoding); + if (i < size) size = i; - } avpriv_init_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx); avpriv_do_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx); - //setup vq_data, which contains a single MB - vq_data[0] = vq_pict_buf; + // set up vq_data, which contains a single MB + vq_data[0] = vq_pict_buf; vq_linesize[0] = MB_SIZE; - vq_data[1] = &vq_pict_buf[MB_AREA]; - vq_data[2] = vq_data[1] + (MB_AREA >> 2); - vq_linesize[1] = vq_linesize[2] = MB_SIZE >> 1; + vq_data[1] = &vq_pict_buf[MB_AREA]; + vq_data[2] = vq_data[1] + (MB_AREA >> 2); + vq_linesize[1] = + vq_linesize[2] = MB_SIZE >> 1; - //copy indices - for(i = j = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, j++) { + // copy indices + for (i = j = y = 0; y < h; y += MB_SIZE) + for (x = 0; x < s->w; x += MB_SIZE, j++) { mb_info *mb = &s->mb[j]; -// skip uninteresting blocks if we know their preferred encoding - if(CERTAIN(encoding) && mb->best_encoding != encoding) + // skip uninteresting blocks if we know their preferred encoding + if (CERTAIN(encoding) && mb->best_encoding != encoding) continue; - //point sub_data to current MB + // point sub_data to current MB get_sub_picture(s, x, y, data, linesize, sub_data, sub_linesize); - if(v1mode) { + if (v1mode) { mb->v1_vector = s->codebook_closest[i]; - //fill in vq_data with V1 data + // fill in vq_data with V1 data decode_v1_vector(s, vq_data, vq_linesize, mb->v1_vector, info); mb->v1_error = compute_mb_distortion(s, sub_data, sub_linesize, vq_data, vq_linesize); total_error += mb->v1_error; } else { - for(k = 0; k < 4; k++) - mb->v4_vector[k] = s->codebook_closest[i+k]; + for (k = 0; k < 4; k++) + mb->v4_vector[k] = s->codebook_closest[i + k]; - //fill in vq_data with V4 data + // fill in vq_data with V4 data decode_v4_vector(s, vq_data, vq_linesize, mb->v4_vector, info); mb->v4_error = compute_mb_distortion(s, sub_data, sub_linesize, @@ -912,12 +820,9 @@ static int quantize(CinepakEncContext *s, int h, } i += v1mode ? 1 : 4; } - } -// check that we did it right in the beginning of the function + // check that we did it right in the beginning of the function av_assert0(i >= size); // training set is no smaller than the codebook - //av_log(s->avctx, AV_LOG_INFO, "isv1 %i size= %i i= %i error %"PRId64"\n", v1mode, size, i, total_error); - return size; } @@ -930,221 +835,160 @@ static void calculate_skip_errors(CinepakEncContext *s, int h, uint8_t *sub_last_data [4], *sub_pict_data [4]; int sub_last_linesize[4], sub_pict_linesize[4]; - for(i = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, i++) { - get_sub_picture(s, x, y, last_data, last_linesize, - sub_last_data, sub_last_linesize); - get_sub_picture(s, x, y, data, linesize, - sub_pict_data, sub_pict_linesize); + for (i = y = 0; y < h; y += MB_SIZE) + for (x = 0; x < s->w; x += MB_SIZE, i++) { + get_sub_picture(s, x, y, last_data, last_linesize, + sub_last_data, sub_last_linesize); + get_sub_picture(s, x, y, data, linesize, + sub_pict_data, sub_pict_linesize); - s->mb[i].skip_error = compute_mb_distortion(s, - sub_last_data, sub_last_linesize, - sub_pict_data, sub_pict_linesize); + s->mb[i].skip_error = + compute_mb_distortion(s, + sub_last_data, sub_last_linesize, + sub_pict_data, sub_pict_linesize); } - } } -static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe, unsigned char *buf, int strip_size) +static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe, + unsigned char *buf, int strip_size) { -// actually we are exclusively using intra strip coding (how much can we win -// otherwise? how to choose which part of a codebook to update?), -// keyframes are different only because we disallow ENC_SKIP on them -- rl -// (besides, the logic here used to be inverted: ) -// buf[0] = keyframe ? 0x11: 0x10; - buf[0] = keyframe ? 0x10: 0x11; + // actually we are exclusively using intra strip coding (how much can we win + // otherwise? how to choose which part of a codebook to update?), + // keyframes are different only because we disallow ENC_SKIP on them -- rl + // (besides, the logic here used to be inverted: ) + // buf[0] = keyframe ? 0x11: 0x10; + buf[0] = keyframe ? 0x10 : 0x11; AV_WB24(&buf[1], strip_size + STRIP_HEADER_SIZE); -// AV_WB16(&buf[4], y); /* using absolute y values works -- rl */ + // AV_WB16(&buf[4], y); /* using absolute y values works -- rl */ AV_WB16(&buf[4], 0); /* using relative values works as well -- rl */ AV_WB16(&buf[6], 0); -// AV_WB16(&buf[8], y+h); /* using absolute y values works -- rl */ + // AV_WB16(&buf[8], y + h); /* using absolute y values works -- rl */ AV_WB16(&buf[8], h); /* using relative values works as well -- rl */ AV_WB16(&buf[10], s->w); - //av_log(s->avctx, AV_LOG_INFO, "write_strip_header() %x keyframe=%d\n", buf[0], keyframe); } static int rd_strip(CinepakEncContext *s, int y, int h, int keyframe, uint8_t *last_data[4], int last_linesize[4], uint8_t *data[4], int linesize[4], uint8_t *scratch_data[4], int scratch_linesize[4], - unsigned char *buf, int64_t *best_score -#ifdef CINEPAK_REPORT_SERR -, int64_t *best_serr -#endif -) + unsigned char *buf, int64_t *best_score) { int64_t score = 0; -#ifdef CINEPAK_REPORT_SERR - int64_t serr; -#endif int best_size = 0; strip_info info; -// for codebook optimization: + // for codebook optimization: int v1enough, v1_size, v4enough, v4_size; int new_v1_size, new_v4_size; int v1shrunk, v4shrunk; - if(!keyframe) + if (!keyframe) calculate_skip_errors(s, h, last_data, last_linesize, data, linesize, &info); - //try some powers of 4 for the size of the codebooks - //constraint the v4 codebook to be no bigger than v1 one, - //(and no less than v1_size/4) - //thus making v1 preferable and possibly losing small details? should be ok + // try some powers of 4 for the size of the codebooks + // constraint the v4 codebook to be no bigger than v1 one, + // (and no less than v1_size/4) + // thus making v1 preferable and possibly losing small details? should be ok #define SMALLEST_CODEBOOK 1 - for(v1enough = 0, v1_size = SMALLEST_CODEBOOK; v1_size <= CODEBOOK_MAX && !v1enough; v1_size <<= 2) { - for(v4enough = 0, v4_size = 0; v4_size <= v1_size && !v4enough; v4_size = v4_size ? v4_size << 2 : v1_size >= SMALLEST_CODEBOOK << 2 ? v1_size >> 2 : SMALLEST_CODEBOOK) { - //try all modes - for(CinepakMode mode = 0; mode < MODE_COUNT; mode++) { - //don't allow MODE_MC in intra frames - if(keyframe && mode == MODE_MC) + for (v1enough = 0, v1_size = SMALLEST_CODEBOOK; v1_size <= CODEBOOK_MAX && !v1enough; v1_size <<= 2) { + for (v4enough = 0, v4_size = 0; v4_size <= v1_size && !v4enough; v4_size = v4_size ? v4_size << 2 : v1_size >= SMALLEST_CODEBOOK << 2 ? v1_size >> 2 : SMALLEST_CODEBOOK) { + CinepakMode mode; + // try all modes + for (mode = 0; mode < MODE_COUNT; mode++) { + // don't allow MODE_MC in intra frames + if (keyframe && mode == MODE_MC) continue; - if(mode == MODE_V1_ONLY) { + if (mode == MODE_V1_ONLY) { info.v1_size = v1_size; -// the size may shrink even before optimizations if the input is short: + // the size may shrink even before optimizations if the input is short: info.v1_size = quantize(s, h, data, linesize, 1, &info, ENC_UNCERTAIN); - if(info.v1_size < v1_size) -// too few eligible blocks, no sense in trying bigger sizes + if (info.v1_size < v1_size) + // too few eligible blocks, no sense in trying bigger sizes v1enough = 1; info.v4_size = 0; } else { // mode != MODE_V1_ONLY // if v4 codebook is empty then only allow V1-only mode - if(!v4_size) + if (!v4_size) continue; - if(mode == MODE_V1_V4) { + if (mode == MODE_V1_V4) { info.v4_size = v4_size; info.v4_size = quantize(s, h, data, linesize, 0, &info, ENC_UNCERTAIN); - if(info.v4_size < v4_size) -// too few eligible blocks, no sense in trying bigger sizes + if (info.v4_size < v4_size) + // too few eligible blocks, no sense in trying bigger sizes v4enough = 1; } } info.mode = mode; -// choose the best encoding per block, based on current experience + // choose the best encoding per block, based on current experience score = calculate_mode_score(s, h, &info, 0, - &v1shrunk, &v4shrunk -#ifdef CINEPAK_REPORT_SERR -, &serr -#endif -); + &v1shrunk, &v4shrunk); - if(mode != MODE_V1_ONLY){ + if (mode != MODE_V1_ONLY) { int extra_iterations_limit = s->max_extra_cb_iterations; -// recompute the codebooks, omitting the extra blocks -// we assume we _may_ come here with more blocks to encode than before + // recompute the codebooks, omitting the extra blocks + // we assume we _may_ come here with more blocks to encode than before info.v1_size = v1_size; new_v1_size = quantize(s, h, data, linesize, 1, &info, ENC_V1); - if(new_v1_size < info.v1_size){ - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v1 codebook to %i entries\n", mode, v1_size, v4_size, new_v1_size); + if (new_v1_size < info.v1_size) info.v1_size = new_v1_size; - } -// we assume we _may_ come here with more blocks to encode than before + // we assume we _may_ come here with more blocks to encode than before info.v4_size = v4_size; new_v4_size = quantize(s, h, data, linesize, 0, &info, ENC_V4); - if(new_v4_size < info.v4_size) { - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v4 codebook to %i entries at first iteration\n", mode, v1_size, v4_size, new_v4_size); + if (new_v4_size < info.v4_size) info.v4_size = new_v4_size; - } -// calculate the resulting score -// (do not move blocks to codebook encodings now, as some blocks may have -// got bigger errors despite a smaller training set - but we do not -// ever grow the training sets back) - for(;;) { + // calculate the resulting score + // (do not move blocks to codebook encodings now, as some blocks may have + // got bigger errors despite a smaller training set - but we do not + // ever grow the training sets back) + for (;;) { score = calculate_mode_score(s, h, &info, 1, - &v1shrunk, &v4shrunk -#ifdef CINEPAK_REPORT_SERR -, &serr -#endif -); -// do we have a reason to reiterate? if so, have we reached the limit? - if((!v1shrunk && !v4shrunk) || !extra_iterations_limit--) break; -// recompute the codebooks, omitting the extra blocks - if(v1shrunk) { + &v1shrunk, &v4shrunk); + // do we have a reason to reiterate? if so, have we reached the limit? + if ((!v1shrunk && !v4shrunk) || !extra_iterations_limit--) + break; + // recompute the codebooks, omitting the extra blocks + if (v1shrunk) { info.v1_size = v1_size; new_v1_size = quantize(s, h, data, linesize, 1, &info, ENC_V1); - if(new_v1_size < info.v1_size){ - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v1 codebook to %i entries\n", mode, v1_size, v4_size, new_v1_size); + if (new_v1_size < info.v1_size) info.v1_size = new_v1_size; - } } - if(v4shrunk) { + if (v4shrunk) { info.v4_size = v4_size; new_v4_size = quantize(s, h, data, linesize, 0, &info, ENC_V4); - if(new_v4_size < info.v4_size) { - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v4 codebook to %i entries\n", mode, v1_size, v4_size, new_v4_size); + if (new_v4_size < info.v4_size) info.v4_size = new_v4_size; - } } } } - //av_log(s->avctx, AV_LOG_INFO, "%3i %3i score = %"PRId64"\n", v1_size, v4_size, score); - - if(best_size == 0 || score < *best_score) { - + if (best_size == 0 || score < *best_score) { *best_score = score; -#ifdef CINEPAK_REPORT_SERR - *best_serr = serr; -#endif best_size = encode_mode(s, h, scratch_data, scratch_linesize, last_data, last_linesize, &info, s->strip_buf + STRIP_HEADER_SIZE); - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: %18"PRId64" %i B", mode, info.v1_size, info.v4_size, score, best_size); - //av_log(s->avctx, AV_LOG_INFO, "\n"); -#ifdef CINEPAK_REPORT_SERR - av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: %18"PRId64" %i B\n", mode, v1_size, v4_size, serr, best_size); -#endif - -#ifdef CINEPAKENC_DEBUG - //save MB encoding choices - memcpy(s->best_mb, s->mb, mb_count*sizeof(mb_info)); -#endif - - //memcpy(strip_temp + STRIP_HEADER_SIZE, strip_temp, best_size); write_strip_header(s, y, h, keyframe, s->strip_buf, best_size); - } } } } -#ifdef CINEPAKENC_DEBUG - //gather stats. this will only work properly of MAX_STRIPS == 1 - if(best_info.mode == MODE_V1_ONLY) { - s->num_v1_mode++; - s->num_v1_encs += s->w*h/MB_AREA; - } else { - if(best_info.mode == MODE_V1_V4) - s->num_v4_mode++; - else - s->num_mc_mode++; - - int x; - for(x = 0; x < s->w*h/MB_AREA; x++) - if(s->best_mb[x].best_encoding == ENC_V1) - s->num_v1_encs++; - else if(s->best_mb[x].best_encoding == ENC_V4) - s->num_v4_encs++; - else - s->num_skips++; - } -#endif - best_size += STRIP_HEADER_SIZE; memcpy(buf, s->strip_buf, best_size); return best_size; } -static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, int num_strips, int data_size, int isakeyframe) +static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, + int num_strips, int data_size, int isakeyframe) { buf[0] = isakeyframe ? 0 : 1; AV_WB24(&buf[1], data_size + CVID_HEADER_SIZE); @@ -1158,91 +1002,93 @@ static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, int num_s static int rd_frame(CinepakEncContext *s, const AVFrame *frame, int isakeyframe, unsigned char *buf, int buf_size) { - int num_strips, strip, i, y, nexty, size, temp_size; + int num_strips, strip, i, y, nexty, size, temp_size, best_size; uint8_t *last_data [4], *data [4], *scratch_data [4]; int last_linesize[4], linesize[4], scratch_linesize[4]; int64_t best_score = 0, score, score_temp; -#ifdef CINEPAK_REPORT_SERR - int64_t best_serr = 0, serr, serr_temp; -#endif + int best_nstrips; - int best_nstrips = -1, best_size = -1; // mark as uninitialzed - - if(s->pix_fmt == AV_PIX_FMT_RGB24) { + if (s->pix_fmt == AV_PIX_FMT_RGB24) { int x; -// build a copy of the given frame in the correct colorspace - for(y = 0; y < s->h; y += 2) { - for(x = 0; x < s->w; x += 2) { - uint8_t *ir[2]; int32_t r, g, b, rr, gg, bb; - ir[0] = frame->data[0] + x*3 + y*frame->linesize[0]; + // build a copy of the given frame in the correct colorspace + for (y = 0; y < s->h; y += 2) + for (x = 0; x < s->w; x += 2) { + uint8_t *ir[2]; + int32_t r, g, b, rr, gg, bb; + ir[0] = frame->data[0] + x * 3 + y * frame->linesize[0]; ir[1] = ir[0] + frame->linesize[0]; get_sub_picture(s, x, y, s->input_frame->data, s->input_frame->linesize, scratch_data, scratch_linesize); r = g = b = 0; - for(i=0; i<4; ++i) { + for (i = 0; i < 4; ++i) { int i1, i2; - i1 = (i&1); i2 = (i>=2); - rr = ir[i2][i1*3+0]; - gg = ir[i2][i1*3+1]; - bb = ir[i2][i1*3+2]; - r += rr; g += gg; b += bb; -// using fixed point arithmetic for portable repeatability, scaling by 2^23 -// "Y" -// rr = 0.2857*rr + 0.5714*gg + 0.1429*bb; - rr = (2396625*rr + 4793251*gg + 1198732*bb) >> 23; - if( rr < 0) rr = 0; - else if (rr > 255) rr = 255; - scratch_data[0][i1 + i2*scratch_linesize[0]] = rr; + i1 = (i & 1); + i2 = (i >= 2); + rr = ir[i2][i1 * 3 + 0]; + gg = ir[i2][i1 * 3 + 1]; + bb = ir[i2][i1 * 3 + 2]; + r += rr; + g += gg; + b += bb; + // using fixed point arithmetic for portable repeatability, scaling by 2^23 + // "Y" + // rr = 0.2857 * rr + 0.5714 * gg + 0.1429 * bb; + rr = (2396625 * rr + 4793251 * gg + 1198732 * bb) >> 23; + if (rr < 0) + rr = 0; + else if (rr > 255) + rr = 255; + scratch_data[0][i1 + i2 * scratch_linesize[0]] = rr; } -// let us scale down as late as possible -// r /= 4; g /= 4; b /= 4; -// "U" -// rr = -0.1429*r - 0.2857*g + 0.4286*b; - rr = (-299683*r - 599156*g + 898839*b) >> 23; - if( rr < -128) rr = -128; - else if (rr > 127) rr = 127; + // let us scale down as late as possible + // r /= 4; g /= 4; b /= 4; + // "U" + // rr = -0.1429 * r - 0.2857 * g + 0.4286 * b; + rr = (-299683 * r - 599156 * g + 898839 * b) >> 23; + if (rr < -128) + rr = -128; + else if (rr > 127) + rr = 127; scratch_data[1][0] = rr + 128; // quantize needs unsigned -// "V" -// rr = 0.3571*r - 0.2857*g - 0.0714*b; - rr = (748893*r - 599156*g - 149737*b) >> 23; - if( rr < -128) rr = -128; - else if (rr > 127) rr = 127; + // "V" + // rr = 0.3571 * r - 0.2857 * g - 0.0714 * b; + rr = (748893 * r - 599156 * g - 149737 * b) >> 23; + if (rr < -128) + rr = -128; + else if (rr > 127) + rr = 127; scratch_data[2][0] = rr + 128; // quantize needs unsigned } - } } - //would be nice but quite certainly incompatible with vintage players: + // would be nice but quite certainly incompatible with vintage players: // support encoding zero strips (meaning skip the whole frame) - for(num_strips = s->min_strips; num_strips <= s->max_strips && num_strips <= s->h / MB_SIZE; num_strips++) { + for (num_strips = s->min_strips; num_strips <= s->max_strips && num_strips <= s->h / MB_SIZE; num_strips++) { score = 0; - size = 0; -#ifdef CINEPAK_REPORT_SERR - serr = 0; -#endif + size = 0; - for(y = 0, strip = 1; y < s->h; strip++, y = nexty) { + for (y = 0, strip = 1; y < s->h; strip++, y = nexty) { int strip_height; nexty = strip * s->h / num_strips; // <= s->h - //make nexty the next multiple of 4 if not already there - if(nexty & 3) + // make nexty the next multiple of 4 if not already there + if (nexty & 3) nexty += 4 - (nexty & 3); strip_height = nexty - y; - if(strip_height <= 0) { // can this ever happen? + if (strip_height <= 0) { // can this ever happen? av_log(s->avctx, AV_LOG_INFO, "skipping zero height strip %i of %i\n", strip, num_strips); continue; } - if(s->pix_fmt == AV_PIX_FMT_RGB24) + if (s->pix_fmt == AV_PIX_FMT_RGB24) get_sub_picture(s, 0, y, s->input_frame->data, s->input_frame->linesize, data, linesize); else get_sub_picture(s, 0, y, - (uint8_t **)frame->data, (int*)frame->linesize, + (uint8_t **)frame->data, (int *)frame->linesize, data, linesize); get_sub_picture(s, 0, y, s->last_frame->data, s->last_frame->linesize, @@ -1251,68 +1097,51 @@ static int rd_frame(CinepakEncContext *s, const AVFrame *frame, s->scratch_frame->data, s->scratch_frame->linesize, scratch_data, scratch_linesize); - if((temp_size = rd_strip(s, y, strip_height, isakeyframe, - last_data, last_linesize, data, linesize, - scratch_data, scratch_linesize, - s->frame_buf + size + CVID_HEADER_SIZE, &score_temp -#ifdef CINEPAK_REPORT_SERR -, &serr_temp -#endif -)) < 0) + if ((temp_size = rd_strip(s, y, strip_height, isakeyframe, + last_data, last_linesize, data, linesize, + scratch_data, scratch_linesize, + s->frame_buf + size + CVID_HEADER_SIZE, + &score_temp)) < 0) return temp_size; score += score_temp; -#ifdef CINEPAK_REPORT_SERR - serr += serr_temp; -#endif size += temp_size; - //av_log(s->avctx, AV_LOG_INFO, "strip %d, isakeyframe=%d", strip, isakeyframe); - //av_log(s->avctx, AV_LOG_INFO, "\n"); } - if(best_score == 0 || score < best_score) { + if (best_score == 0 || score < best_score) { best_score = score; -#ifdef CINEPAK_REPORT_SERR - best_serr = serr; -#endif best_size = size + write_cvid_header(s, s->frame_buf, num_strips, size, isakeyframe); - //av_log(s->avctx, AV_LOG_INFO, "best number of strips so far: %2i, %12"PRId64", %i B\n", num_strips, score, best_size); -#ifdef CINEPAK_REPORT_SERR - av_log(s->avctx, AV_LOG_INFO, "best number of strips so far: %2i, %12"PRId64", %i B\n", num_strips, serr, best_size); -#endif FFSWAP(AVFrame *, s->best_frame, s->scratch_frame); memcpy(buf, s->frame_buf, best_size); best_nstrips = num_strips; } -// avoid trying too many strip numbers without a real reason -// (this makes the processing of the very first frame faster) - if(num_strips - best_nstrips > 4) + // avoid trying too many strip numbers without a real reason + // (this makes the processing of the very first frame faster) + if (num_strips - best_nstrips > 4) break; } - av_assert0(best_nstrips >= 0 && best_size >= 0); - -// let the number of strips slowly adapt to the changes in the contents, -// compared to full bruteforcing every time this will occasionally lead -// to some r/d performance loss but makes encoding up to several times faster - if(!s->strip_number_delta_range) { - if(best_nstrips == s->max_strips) { // let us try to step up + // let the number of strips slowly adapt to the changes in the contents, + // compared to full bruteforcing every time this will occasionally lead + // to some r/d performance loss but makes encoding up to several times faster + if (!s->strip_number_delta_range) { + if (best_nstrips == s->max_strips) { // let us try to step up s->max_strips = best_nstrips + 1; - if(s->max_strips >= s->max_max_strips) + if (s->max_strips >= s->max_max_strips) s->max_strips = s->max_max_strips; } else { // try to step down s->max_strips = best_nstrips; } s->min_strips = s->max_strips - 1; - if(s->min_strips < s->min_min_strips) + if (s->min_strips < s->min_min_strips) s->min_strips = s->min_min_strips; } else { s->max_strips = best_nstrips + s->strip_number_delta_range; - if(s->max_strips >= s->max_max_strips) + if (s->max_strips >= s->max_max_strips) s->max_strips = s->max_max_strips; s->min_strips = best_nstrips - s->strip_number_delta_range; - if(s->min_strips < s->min_min_strips) + if (s->min_strips < s->min_min_strips) s->min_strips = s->min_min_strips; } @@ -1329,7 +1158,7 @@ static int cinepak_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if ((ret = ff_alloc_packet2(avctx, pkt, s->frame_buf_size, 0)) < 0) return ret; - ret = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size); + ret = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size); pkt->size = ret; if (s->curframe == 0) pkt->flags |= AV_PKT_FLAG_KEY; @@ -1358,30 +1187,22 @@ static av_cold int cinepak_encode_end(AVCodecContext *avctx) av_freep(&s->strip_buf); av_freep(&s->frame_buf); av_freep(&s->mb); -#ifdef CINEPAKENC_DEBUG - av_freep(&s->best_mb); -#endif - for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) + for (x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) av_freep(&s->pict_bufs[x]); -#ifdef CINEPAKENC_DEBUG - av_log(avctx, AV_LOG_INFO, "strip coding stats: %i V1 mode, %i V4 mode, %i MC mode (%i V1 encs, %i V4 encs, %i skips)\n", - s->num_v1_mode, s->num_v4_mode, s->num_mc_mode, s->num_v1_encs, s->num_v4_encs, s->num_skips); -#endif - return 0; } AVCodec ff_cinepak_encoder = { .name = "cinepak", + .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_CINEPAK, .priv_data_size = sizeof(CinepakEncContext), .init = cinepak_encode_init, .encode2 = cinepak_encode_frame, .close = cinepak_encode_end, - .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }, .priv_class = &cinepak_class, }; diff --git a/libavcodec/clearvideo.c b/libavcodec/clearvideo.c index 067942a13..2c06b79fd 100644 --- a/libavcodec/clearvideo.c +++ b/libavcodec/clearvideo.c @@ -25,10 +25,10 @@ */ #include "avcodec.h" +#include "bytestream.h" +#include "get_bits.h" #include "idctdsp.h" #include "internal.h" -#include "get_bits.h" -#include "bytestream.h" #define NUM_DC_CODES 127 #define NUM_AC_CODES 103 @@ -129,6 +129,7 @@ typedef struct CLVContext { int luma_dc_quant, chroma_dc_quant, ac_quant; DECLARE_ALIGNED(16, int16_t, block)[64]; int top_dc[3], left_dc[4]; + int iframes_warning; } CLVContext; static inline int decode_block(CLVContext *ctx, int16_t *blk, int has_ac, @@ -179,12 +180,12 @@ static inline int decode_block(CLVContext *ctx, int16_t *blk, int has_ac, } #define DCT_TEMPLATE(blk, step, bias, shift, dshift, OP) \ - const int t0 = OP( 2841 * blk[1 * step] + 565 * blk[7 * step]); \ - const int t1 = OP( 565 * blk[1 * step] - 2841 * blk[7 * step]); \ - const int t2 = OP( 1609 * blk[5 * step] + 2408 * blk[3 * step]); \ - const int t3 = OP( 2408 * blk[5 * step] - 1609 * blk[3 * step]); \ - const int t4 = OP( 1108 * blk[2 * step] - 2676 * blk[6 * step]); \ - const int t5 = OP( 2676 * blk[2 * step] + 1108 * blk[6 * step]); \ + const int t0 = OP(2841 * blk[1 * step] + 565 * blk[7 * step]); \ + const int t1 = OP( 565 * blk[1 * step] - 2841 * blk[7 * step]); \ + const int t2 = OP(1609 * blk[5 * step] + 2408 * blk[3 * step]); \ + const int t3 = OP(2408 * blk[5 * step] - 1609 * blk[3 * step]); \ + const int t4 = OP(1108 * blk[2 * step] - 2676 * blk[6 * step]); \ + const int t5 = OP(2676 * blk[2 * step] + 1108 * blk[6 * step]); \ const int t6 = ((blk[0 * step] + blk[4 * step]) * (1 << dshift)) + bias; \ const int t7 = ((blk[0 * step] - blk[4 * step]) * (1 << dshift)) + bias; \ const int t8 = t0 + t2; \ @@ -225,9 +226,7 @@ static void clv_dct(int16_t *block) static int decode_mb(CLVContext *c, int x, int y) { - int i; - int has_ac[6]; - int off; + int i, has_ac[6], off; for (i = 0; i < 6; i++) has_ac[i] = get_bits1(&c->gb); @@ -247,7 +246,8 @@ static int decode_mb(CLVContext *c, int x, int y) clv_dct(c->block); if (i == 2) off += c->pic->linesize[0] * 8; - c->idsp.put_pixels_clamped(c->block, c->pic->data[0] + off + (i & 1) * 8, + c->idsp.put_pixels_clamped(c->block, + c->pic->data[0] + off + (i & 1) * 8, c->pic->linesize[0]); } @@ -279,12 +279,11 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, CLVContext *c = avctx->priv_data; GetByteContext gb; uint32_t frame_type; - int i, j; - int ret; + int i, j, ret; int mb_ret = 0; bytestream2_init(&gb, buf, buf_size); - if (avctx->codec_tag == MKTAG('C','L','V','1')) { + if (avctx->codec_tag == MKTAG('C', 'L', 'V', '1')) { int skip = bytestream2_get_byte(&gb); bytestream2_skip(&gb, (skip + 1) * 8); } @@ -301,7 +300,8 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, return ret; c->pic->key_frame = frame_type & 0x20 ? 1 : 0; - c->pic->pict_type = frame_type & 0x20 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + c->pic->pict_type = frame_type & 0x20 ? AV_PICTURE_TYPE_I + : AV_PICTURE_TYPE_P; bytestream2_get_be32(&gb); // frame size; c->ac_quant = bytestream2_get_byte(&gb); @@ -309,7 +309,7 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, c->chroma_dc_quant = 32; if ((ret = init_get_bits8(&c->gb, buf + bytestream2_tell(&gb), - (buf_size - bytestream2_tell(&gb)))) < 0) + buf_size - bytestream2_tell(&gb))) < 0) return ret; for (i = 0; i < 3; i++) @@ -330,6 +330,10 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, *got_frame = 1; } else { + if (!c->iframes_warning) + avpriv_report_missing_feature(avctx, "Non-I-frames in Clearvideo"); + c->iframes_warning = 1; + return AVERROR_PATCHWELCOME; } return mb_ret < 0 ? mb_ret : buf_size; @@ -337,20 +341,19 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, static av_cold int clv_decode_init(AVCodecContext *avctx) { - CLVContext * const c = avctx->priv_data; + CLVContext *const c = avctx->priv_data; int ret; - c->avctx = avctx; - avctx->pix_fmt = AV_PIX_FMT_YUV420P; - c->pic = av_frame_alloc(); + c->avctx = avctx; + c->mb_width = FFALIGN(avctx->width, 16) >> 4; + c->mb_height = FFALIGN(avctx->height, 16) >> 4; + c->iframes_warning = 0; + c->pic = av_frame_alloc(); if (!c->pic) return AVERROR(ENOMEM); - c->mb_width = FFALIGN(avctx->width, 16) >> 4; - c->mb_height = FFALIGN(avctx->height, 16) >> 4; - ff_idctdsp_init(&c->idsp, avctx); ret = init_vlc(&c->dc_vlc, 9, NUM_DC_CODES, clv_dc_bits, 1, 1, @@ -373,7 +376,7 @@ static av_cold int clv_decode_init(AVCodecContext *avctx) static av_cold int clv_decode_end(AVCodecContext *avctx) { - CLVContext * const c = avctx->priv_data; + CLVContext *const c = avctx->priv_data; av_frame_free(&c->pic); @@ -385,6 +388,7 @@ static av_cold int clv_decode_end(AVCodecContext *avctx) AVCodec ff_clearvideo_decoder = { .name = "clearvideo", + .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_CLEARVIDEO, .priv_data_size = sizeof(CLVContext), @@ -392,5 +396,5 @@ AVCodec ff_clearvideo_decoder = { .close = clv_decode_end, .decode = clv_decode_frame, .capabilities = AV_CODEC_CAP_DR1, - .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c index 1e884f3c3..28432ac71 100644 --- a/libavcodec/cngdec.c +++ b/libavcodec/cngdec.c @@ -153,7 +153,7 @@ static int cng_decode_frame(AVCodecContext *avctx, void *data, return ret; buf_out = (int16_t *)frame->data[0]; for (i = 0; i < avctx->frame_size; i++) - buf_out[i] = p->filter_out[i + p->order]; + buf_out[i] = av_clip_int16(p->filter_out[i + p->order]); memcpy(p->filter_out, p->filter_out + avctx->frame_size, p->order * sizeof(*p->filter_out)); diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 6a13bbbf0..c3688de1d 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -46,15 +46,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles), }, -#if FF_API_XVMC - { - .id = AV_CODEC_ID_MPEG2VIDEO_XVMC, - .type = AVMEDIA_TYPE_VIDEO, - .name = "mpegvideo_xvmc", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video XvMC (X-Video Motion Compensation)"), - .props = AV_CODEC_PROP_LOSSY, - }, -#endif /* FF_API_XVMC */ { .id = AV_CODEC_ID_H261, .type = AVMEDIA_TYPE_VIDEO, @@ -2499,15 +2490,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ATRAC3 (Adaptive TRansform Acoustic Coding 3)"), .props = AV_CODEC_PROP_LOSSY, }, -#if FF_API_VOXWARE - { - .id = AV_CODEC_ID_VOXWARE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "voxware", - .long_name = NULL_IF_CONFIG_SMALL("Voxware RT29 Metasound"), - .props = AV_CODEC_PROP_LOSSY, - }, -#endif { .id = AV_CODEC_ID_APE, .type = AVMEDIA_TYPE_AUDIO, @@ -2877,6 +2859,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM MTAF"), .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, + }, /* subtitle codecs */ { diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c index 83bc8bf36..e3c595596 100644 --- a/libavcodec/crystalhd.c +++ b/libavcodec/crystalhd.c @@ -786,8 +786,9 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame) .receive_frame = crystalhd_receive_frame, \ .flush = flush, \ .bsfs = bsf_name, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \ + .wrapper_name = "crystalhd", \ }; #if CONFIG_H264_CRYSTALHD_DECODER diff --git a/libavcodec/cuvid.c b/libavcodec/cuviddec.c similarity index 98% rename from libavcodec/cuvid.c rename to libavcodec/cuviddec.c index 2ba8e00c6..c23033c7e 100644 --- a/libavcodec/cuvid.c +++ b/libavcodec/cuviddec.c @@ -32,6 +32,7 @@ #include "avcodec.h" #include "decode.h" +#include "hwaccel.h" #include "internal.h" typedef struct CuvidContext @@ -835,7 +836,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) goto error; } - ret = cuvid_load_functions(&ctx->cvdl); + ret = cuvid_load_functions(&ctx->cvdl, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n"); goto error; @@ -1094,6 +1095,19 @@ static const AVOption options[] = { { NULL } }; +static const AVCodecHWConfigInternal *cuvid_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_CUDA, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | + AV_CODEC_HW_CONFIG_METHOD_INTERNAL, + .device_type = AV_HWDEVICE_TYPE_CUDA + }, + .hwaccel = NULL, + }, + NULL +}; + #define DEFINE_CUVID_CODEC(x, X) \ static const AVClass x##_cuvid_class = { \ .class_name = #x "_cuvid", \ @@ -1101,12 +1115,6 @@ static const AVOption options[] = { .option = options, \ .version = LIBAVUTIL_VERSION_INT, \ }; \ - AVHWAccel ff_##x##_cuvid_hwaccel = { \ - .name = #x "_cuvid", \ - .type = AVMEDIA_TYPE_VIDEO, \ - .id = AV_CODEC_ID_##X, \ - .pix_fmt = AV_PIX_FMT_CUDA, \ - }; \ AVCodec ff_##x##_cuvid_decoder = { \ .name = #x "_cuvid", \ .long_name = NULL_IF_CONFIG_SMALL("Nvidia CUVID " #X " decoder"), \ @@ -1119,12 +1127,14 @@ static const AVOption options[] = { .decode = cuvid_decode_frame, \ .receive_frame = cuvid_output_frame, \ .flush = cuvid_flush, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \ AV_PIX_FMT_NV12, \ AV_PIX_FMT_P010, \ AV_PIX_FMT_P016, \ AV_PIX_FMT_NONE }, \ + .hw_configs = cuvid_hw_configs, \ + .wrapper_name = "cuvid", \ }; #if CONFIG_HEVC_CUVID_DECODER diff --git a/libavcodec/dca.c b/libavcodec/dca.c index 307b21471..a0729e61a 100644 --- a/libavcodec/dca.c +++ b/libavcodec/dca.c @@ -146,12 +146,17 @@ int ff_dca_parse_core_frame_header(DCACoreFrameHeader *h, GetBitContext *gb) return 0; } -int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, uint8_t *buf, int size) +int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, const uint8_t *buf, int size) { GetBitContext gb; + int ret; - if (init_get_bits8(&gb, buf, size) < 0) - return DCA_PARSE_ERROR_INVALIDDATA; + ret = init_get_bits8(&gb, buf, size); + if (ret < 0) + return ret; - return ff_dca_parse_core_frame_header(h, &gb); + if (ff_dca_parse_core_frame_header(h, &gb) < 0) + return AVERROR_INVALIDDATA; + + return 0; } diff --git a/libavcodec/dca.h b/libavcodec/dca.h index 172c965b3..e96c589c0 100644 --- a/libavcodec/dca.h +++ b/libavcodec/dca.h @@ -29,10 +29,10 @@ #include #include "libavutil/common.h" -#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "get_bits.h" +#include "internal.h" #define DCA_CORE_FRAME_HEADER_SIZE 18 @@ -46,7 +46,6 @@ enum DCAParseError { DCA_PARSE_ERROR_RESERVED_BIT = -7, DCA_PARSE_ERROR_LFE_FLAG = -8, DCA_PARSE_ERROR_PCM_RES = -9, - DCA_PARSE_ERROR_INVALIDDATA = -10, }; typedef struct DCACoreFrameHeader { @@ -196,7 +195,7 @@ enum DCADownMixType { DCA_DMIX_TYPE_COUNT }; -extern av_export const uint32_t avpriv_dca_sample_rates[16]; +extern av_export_avcodec const uint32_t avpriv_dca_sample_rates[16]; extern const uint32_t ff_dca_sampling_freqs[16]; extern const uint8_t ff_dca_freq_ranges[16]; @@ -211,10 +210,19 @@ int avpriv_dca_convert_bitstream(const uint8_t *src, int src_size, uint8_t *dst, /** * Parse and validate core frame header + * @param[out] h Pointer to struct where header info is written. + * @param[in] buf Pointer to the data buffer + * @param[in] size Size of the data buffer + * @return 0 on success, negative AVERROR code on failure + */ +int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, const uint8_t *buf, int size); + +/** + * Parse and validate core frame header + * @param[out] h Pointer to struct where header info is written. + * @param[in] gbc BitContext containing the first 120 bits of the frame. * @return 0 on success, negative DCA_PARSE_ERROR_ code on failure */ -int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, uint8_t *buf, int size); - int ff_dca_parse_core_frame_header(DCACoreFrameHeader *h, GetBitContext *gb); #endif /* AVCODEC_DCA_H */ diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index dd601ffae..186997c63 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -21,6 +21,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FFT_FLOAT 0 +#define FFT_FIXED_32 1 + #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" @@ -33,6 +36,7 @@ #include "dca_core.h" #include "dcadata.h" #include "dcaenc.h" +#include "fft.h" #include "internal.h" #include "mathops.h" #include "put_bits.h" @@ -48,6 +52,8 @@ #define SUBBAND_SAMPLES (SUBFRAMES * SUBSUBFRAMES * 8) #define AUBANDS 25 +#define COS_T(x) (c->cos_table[(x) & 2047]) + typedef struct CompressionOptions { int adpcm_mode; } CompressionOptions; @@ -56,6 +62,7 @@ typedef struct DCAEncContext { AVClass *class; PutBitContext pb; DCAADPCMEncContext adpcm_ctx; + FFTContext mdct; CompressionOptions options; int frame_size; int frame_bits; @@ -92,15 +99,15 @@ typedef struct DCAEncContext { int32_t worst_noise_ever; int consumed_bits; int consumed_adpcm_bits; ///< Number of bits to transmit ADPCM related info -} DCAEncContext; -static int32_t cos_table[2048]; -static int32_t band_interpolation[2][512]; -static int32_t band_spectrum[2][8]; -static int32_t auf[9][AUBANDS][256]; -static int32_t cb_to_add[256]; -static int32_t cb_to_level[2048]; -static int32_t lfe_fir_64i[512]; + int32_t cos_table[2048]; + int32_t band_interpolation_tab[2][512]; + int32_t band_spectrum_tab[2][8]; + int32_t auf[9][AUBANDS][256]; + int32_t cb_to_add[256]; + int32_t cb_to_level[2048]; + int32_t lfe_fir_64i[512]; +} DCAEncContext; /* Transfer function of outer and middle ear, Hz -> dB */ static double hom(double f) @@ -153,15 +160,16 @@ static int encode_init(AVCodecContext *avctx) { DCAEncContext *c = avctx->priv_data; uint64_t layout = avctx->channel_layout; - int i, j, min_frame_bits; + int i, j, k, min_frame_bits; + int ret; if (subband_bufer_alloc(c)) return AVERROR(ENOMEM); c->fullband_channels = c->channels = avctx->channels; c->lfe_channel = (avctx->channels == 3 || avctx->channels == 6); - c->band_interpolation = band_interpolation[1]; - c->band_spectrum = band_spectrum[1]; + c->band_interpolation = c->band_interpolation_tab[1]; + c->band_spectrum = c->band_spectrum_tab[1]; c->worst_quantization_noise = -2047; c->worst_noise_ever = -2047; c->consumed_adpcm_bits = 0; @@ -231,93 +239,79 @@ static int encode_init(AVCodecContext *avctx) avctx->frame_size = 32 * SUBBAND_SAMPLES; - if (!cos_table[0]) { - int j, k; + if ((ret = ff_mdct_init(&c->mdct, 9, 0, 1.0)) < 0) + return ret; - cos_table[0] = 0x7fffffff; - cos_table[512] = 0; - cos_table[1024] = -cos_table[0]; - for (i = 1; i < 512; i++) { - cos_table[i] = (int32_t)(0x7fffffff * cos(M_PI * i / 1024)); - cos_table[1024-i] = -cos_table[i]; - cos_table[1024+i] = -cos_table[i]; - cos_table[2048-i] = cos_table[i]; - } - for (i = 0; i < 2048; i++) { - cb_to_level[i] = (int32_t)(0x7fffffff * ff_exp10(-0.005 * i)); - } + /* Init all tables */ + c->cos_table[0] = 0x7fffffff; + c->cos_table[512] = 0; + c->cos_table[1024] = -c->cos_table[0]; + for (i = 1; i < 512; i++) { + c->cos_table[i] = (int32_t)(0x7fffffff * cos(M_PI * i / 1024)); + c->cos_table[1024-i] = -c->cos_table[i]; + c->cos_table[1024+i] = -c->cos_table[i]; + c->cos_table[2048-i] = +c->cos_table[i]; + } - for (k = 0; k < 32; k++) { - for (j = 0; j < 8; j++) { - lfe_fir_64i[64 * j + k] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); - lfe_fir_64i[64 * (7-j) + (63 - k)] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); - } - } + for (i = 0; i < 2048; i++) + c->cb_to_level[i] = (int32_t)(0x7fffffff * ff_exp10(-0.005 * i)); - for (i = 0; i < 512; i++) { - band_interpolation[0][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_perfect[i]); - band_interpolation[1][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_nonperfect[i]); - } - - for (i = 0; i < 9; i++) { - for (j = 0; j < AUBANDS; j++) { - for (k = 0; k < 256; k++) { - double freq = sample_rates[i] * (k + 0.5) / 512; - - auf[i][j][k] = (int32_t)(10 * (hom(freq) + gammafilter(j, freq))); - } - } - } - - for (i = 0; i < 256; i++) { - double add = 1 + ff_exp10(-0.01 * i); - cb_to_add[i] = (int32_t)(100 * log10(add)); - } + for (k = 0; k < 32; k++) { for (j = 0; j < 8; j++) { - double accum = 0; - for (i = 0; i < 512; i++) { - double reconst = ff_dca_fir_32bands_perfect[i] * ((i & 64) ? (-1) : 1); - accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); - } - band_spectrum[0][j] = (int32_t)(200 * log10(accum)); - } - for (j = 0; j < 8; j++) { - double accum = 0; - for (i = 0; i < 512; i++) { - double reconst = ff_dca_fir_32bands_nonperfect[i] * ((i & 64) ? (-1) : 1); - accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); - } - band_spectrum[1][j] = (int32_t)(200 * log10(accum)); + c->lfe_fir_64i[64 * j + k] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); + c->lfe_fir_64i[64 * (7-j) + (63 - k)] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); } } + + for (i = 0; i < 512; i++) { + c->band_interpolation_tab[0][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_perfect[i]); + c->band_interpolation_tab[1][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_nonperfect[i]); + } + + for (i = 0; i < 9; i++) { + for (j = 0; j < AUBANDS; j++) { + for (k = 0; k < 256; k++) { + double freq = sample_rates[i] * (k + 0.5) / 512; + + c->auf[i][j][k] = (int32_t)(10 * (hom(freq) + gammafilter(j, freq))); + } + } + } + + for (i = 0; i < 256; i++) { + double add = 1 + ff_exp10(-0.01 * i); + c->cb_to_add[i] = (int32_t)(100 * log10(add)); + } + for (j = 0; j < 8; j++) { + double accum = 0; + for (i = 0; i < 512; i++) { + double reconst = ff_dca_fir_32bands_perfect[i] * ((i & 64) ? (-1) : 1); + accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); + } + c->band_spectrum_tab[0][j] = (int32_t)(200 * log10(accum)); + } + for (j = 0; j < 8; j++) { + double accum = 0; + for (i = 0; i < 512; i++) { + double reconst = ff_dca_fir_32bands_nonperfect[i] * ((i & 64) ? (-1) : 1); + accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); + } + c->band_spectrum_tab[1][j] = (int32_t)(200 * log10(accum)); + } + return 0; } static av_cold int encode_close(AVCodecContext *avctx) { - if (avctx->priv_data) { - DCAEncContext *c = avctx->priv_data; - subband_bufer_free(c); - ff_dcaadpcm_free(&c->adpcm_ctx); - } + DCAEncContext *c = avctx->priv_data; + ff_mdct_end(&c->mdct); + subband_bufer_free(c); + ff_dcaadpcm_free(&c->adpcm_ctx); + return 0; } -static inline int32_t cos_t(int x) -{ - return cos_table[x & 2047]; -} - -static inline int32_t sin_t(int x) -{ - return cos_t(x - 512); -} - -static inline int32_t half32(int32_t a) -{ - return (a + 1) >> 1; -} - static void subband_transform(DCAEncContext *c, const int32_t *input) { int ch, subs, i, k, j; @@ -353,7 +347,7 @@ static void subband_transform(DCAEncContext *c, const int32_t *input) resp = 0; for (i = 16; i < 48; i++) { int s = (2 * band + 1) * (2 * (i + 16) + 1); - resp += mul32(accum[i], cos_t(s << 3)) >> 3; + resp += mul32(accum[i], COS_T(s << 3)) >> 3; } c->subband[ch][band][subs] = ((band + 1) & 2) ? -resp : resp; @@ -384,9 +378,9 @@ static void lfe_downsample(DCAEncContext *c, const int32_t *input) accum = 0; for (i = hist_start, j = 0; i < 512; i++, j++) - accum += mul32(hist[i], lfe_fir_64i[j]); + accum += mul32(hist[i], c->lfe_fir_64i[j]); for (i = 0; i < hist_start; i++, j++) - accum += mul32(hist[i], lfe_fir_64i[j]); + accum += mul32(hist[i], c->lfe_fir_64i[j]); c->downsampled_lfe[lfes] = accum; @@ -398,131 +392,72 @@ static void lfe_downsample(DCAEncContext *c, const int32_t *input) } } -typedef struct { - int32_t re; - int32_t im; -} cplx32; - -static void fft(const int32_t in[2 * 256], cplx32 out[256]) +static int32_t get_cb(DCAEncContext *c, int32_t in) { - cplx32 buf[256], rin[256], rout[256]; - int i, j, k, l; + int i, res = 0; + in = FFABS(in); - /* do two transforms in parallel */ - for (i = 0; i < 256; i++) { - /* Apply the Hann window */ - rin[i].re = mul32(in[2 * i], 0x3fffffff - (cos_t(8 * i + 2) >> 1)); - rin[i].im = mul32(in[2 * i + 1], 0x3fffffff - (cos_t(8 * i + 6) >> 1)); - } - /* pre-rotation */ - for (i = 0; i < 256; i++) { - buf[i].re = mul32(cos_t(4 * i + 2), rin[i].re) - - mul32(sin_t(4 * i + 2), rin[i].im); - buf[i].im = mul32(cos_t(4 * i + 2), rin[i].im) - + mul32(sin_t(4 * i + 2), rin[i].re); - } - - for (j = 256, l = 1; j != 1; j >>= 1, l <<= 1) { - for (k = 0; k < 256; k += j) { - for (i = k; i < k + j / 2; i++) { - cplx32 sum, diff; - int t = 8 * l * i; - - sum.re = buf[i].re + buf[i + j / 2].re; - sum.im = buf[i].im + buf[i + j / 2].im; - - diff.re = buf[i].re - buf[i + j / 2].re; - diff.im = buf[i].im - buf[i + j / 2].im; - - buf[i].re = half32(sum.re); - buf[i].im = half32(sum.im); - - buf[i + j / 2].re = mul32(diff.re, cos_t(t)) - - mul32(diff.im, sin_t(t)); - buf[i + j / 2].im = mul32(diff.im, cos_t(t)) - + mul32(diff.re, sin_t(t)); - } - } - } - /* post-rotation */ - for (i = 0; i < 256; i++) { - int b = ff_reverse[i]; - rout[i].re = mul32(buf[b].re, cos_t(4 * i)) - - mul32(buf[b].im, sin_t(4 * i)); - rout[i].im = mul32(buf[b].im, cos_t(4 * i)) - + mul32(buf[b].re, sin_t(4 * i)); - } - for (i = 0; i < 256; i++) { - /* separate the results of the two transforms */ - cplx32 o1, o2; - - o1.re = rout[i].re - rout[255 - i].re; - o1.im = rout[i].im + rout[255 - i].im; - - o2.re = rout[i].im - rout[255 - i].im; - o2.im = -rout[i].re - rout[255 - i].re; - - /* combine them into one long transform */ - out[i].re = mul32( o1.re + o2.re, cos_t(2 * i + 1)) - + mul32( o1.im - o2.im, sin_t(2 * i + 1)); - out[i].im = mul32( o1.im + o2.im, cos_t(2 * i + 1)) - + mul32(-o1.re + o2.re, sin_t(2 * i + 1)); - } -} - -static int32_t get_cb(int32_t in) -{ - int i, res; - - res = 0; - if (in < 0) - in = -in; for (i = 1024; i > 0; i >>= 1) { - if (cb_to_level[i + res] >= in) + if (c->cb_to_level[i + res] >= in) res += i; } return -res; } -static int32_t add_cb(int32_t a, int32_t b) +static int32_t add_cb(DCAEncContext *c, int32_t a, int32_t b) { if (a < b) FFSWAP(int32_t, a, b); if (a - b >= 256) return a; - return a + cb_to_add[a - b]; + return a + c->cb_to_add[a - b]; } -static void adjust_jnd(int samplerate_index, +static void calc_power(DCAEncContext *c, + const int32_t in[2 * 256], int32_t power[256]) +{ + int i; + LOCAL_ALIGNED_32(int32_t, data, [512]); + LOCAL_ALIGNED_32(int32_t, coeff, [256]); + + for (i = 0; i < 512; i++) + data[i] = norm__(mul32(in[i], 0x3fffffff - (COS_T(4 * i + 2) >> 1)), 4); + + c->mdct.mdct_calc(&c->mdct, coeff, data); + for (i = 0; i < 256; i++) { + const int32_t cb = get_cb(c, coeff[i]); + power[i] = add_cb(c, cb, cb); + } +} + +static void adjust_jnd(DCAEncContext *c, const int32_t in[512], int32_t out_cb[256]) { int32_t power[256]; - cplx32 out[256]; int32_t out_cb_unnorm[256]; int32_t denom; const int32_t ca_cb = -1114; const int32_t cs_cb = 928; + const int samplerate_index = c->samplerate_index; int i, j; - fft(in, out); + calc_power(c, in, power); - for (j = 0; j < 256; j++) { - power[j] = add_cb(get_cb(out[j].re), get_cb(out[j].im)); + for (j = 0; j < 256; j++) out_cb_unnorm[j] = -2047; /* and can only grow */ - } for (i = 0; i < AUBANDS; i++) { denom = ca_cb; /* and can only grow */ for (j = 0; j < 256; j++) - denom = add_cb(denom, power[j] + auf[samplerate_index][i][j]); + denom = add_cb(c, denom, power[j] + c->auf[samplerate_index][i][j]); for (j = 0; j < 256; j++) - out_cb_unnorm[j] = add_cb(out_cb_unnorm[j], - -denom + auf[samplerate_index][i][j]); + out_cb_unnorm[j] = add_cb(c, out_cb_unnorm[j], + -denom + c->auf[samplerate_index][i][j]); } for (j = 0; j < 256; j++) - out_cb[j] = add_cb(out_cb[j], -out_cb_unnorm[j] - ca_cb - cs_cb); + out_cb[j] = add_cb(c, out_cb[j], -out_cb_unnorm[j] - ca_cb - cs_cb); } typedef void (*walk_band_t)(DCAEncContext *c, int band1, int band2, int f, @@ -586,7 +521,7 @@ static void calc_masking(DCAEncContext *c, const int32_t *input) data[i] = c->history[ch][k]; for (k -= 512; i < 512; i++, k++) data[i] = input[k * c->channels + chi]; - adjust_jnd(c->samplerate_index, data, c->masking_curve_cb[ssf]); + adjust_jnd(c, data, c->masking_curve_cb[ssf]); } for (i = 0; i < 256; i++) { int32_t m = 2048; @@ -604,16 +539,16 @@ static void calc_masking(DCAEncContext *c, const int32_t *input) } } -static inline int32_t find_peak(const int32_t *in, int len) { +static inline int32_t find_peak(DCAEncContext *c, const int32_t *in, int len) +{ int sample; int32_t m = 0; for (sample = 0; sample < len; sample++) { int32_t s = abs(in[sample]); - if (m < s) { + if (m < s) m = s; - } } - return get_cb(m); + return get_cb(c, m); } static void find_peaks(DCAEncContext *c) @@ -621,14 +556,13 @@ static void find_peaks(DCAEncContext *c) int band, ch; for (ch = 0; ch < c->fullband_channels; ch++) { - for (band = 0; band < 32; band++) { - c->peak_cb[ch][band] = find_peak(c->subband[ch][band], SUBBAND_SAMPLES); - } + for (band = 0; band < 32; band++) + c->peak_cb[ch][band] = find_peak(c, c->subband[ch][band], + SUBBAND_SAMPLES); } - if (c->lfe_channel) { - c->lfe_peak_cb = find_peak(c->downsampled_lfe, DCA_LFE_SAMPLES); - } + if (c->lfe_channel) + c->lfe_peak_cb = find_peak(c, c->downsampled_lfe, DCA_LFE_SAMPLES); } static void adpcm_analysis(DCAEncContext *c) @@ -642,11 +576,12 @@ static void adpcm_analysis(DCAEncContext *c) for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { samples = c->subband[ch][band] - DCA_ADPCM_COEFFS; - pred_vq_id = ff_dcaadpcm_subband_analysis(&c->adpcm_ctx, samples, SUBBAND_SAMPLES, estimated_diff); + pred_vq_id = ff_dcaadpcm_subband_analysis(&c->adpcm_ctx, samples, + SUBBAND_SAMPLES, estimated_diff); if (pred_vq_id >= 0) { c->prediction_mode[ch][band] = pred_vq_id; c->consumed_adpcm_bits += 12; //12 bits to transmit prediction vq index - c->diff_peak_cb[ch][band] = find_peak(estimated_diff, 16); + c->diff_peak_cb[ch][band] = find_peak(c, estimated_diff, 16); } else { c->prediction_mode[ch][band] = -1; } @@ -658,7 +593,7 @@ static const int snr_fudge = 128; #define USED_1ABITS 1 #define USED_26ABITS 4 -static inline int32_t get_step_size(const DCAEncContext *c, int ch, int band) +static inline int32_t get_step_size(DCAEncContext *c, int ch, int band) { int32_t step_size; @@ -670,7 +605,8 @@ static inline int32_t get_step_size(const DCAEncContext *c, int ch, int band) return step_size; } -static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant) +static int calc_one_scale(DCAEncContext *c, int32_t peak_cb, int abits, + softfloat *quant) { int32_t peak; int our_nscale, try_remove; @@ -680,7 +616,7 @@ static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant) av_assert0(peak_cb >= -2047); our_nscale = 127; - peak = cb_to_level[-peak_cb]; + peak = c->cb_to_level[-peak_cb]; for (try_remove = 64; try_remove > 0; try_remove >>= 1) { if (scalefactor_inv[our_nscale - try_remove].e + stepsize_inv[abits].e <= 17) @@ -706,15 +642,17 @@ static inline void quantize_adpcm_subband(DCAEncContext *c, int ch, int band) { int32_t step_size; int32_t diff_peak_cb = c->diff_peak_cb[ch][band]; - c->scale_factor[ch][band] = calc_one_scale(diff_peak_cb, + c->scale_factor[ch][band] = calc_one_scale(c, diff_peak_cb, c->abits[ch][band], &c->quant[ch][band]); step_size = get_step_size(c, ch, band); ff_dcaadpcm_do_real(c->prediction_mode[ch][band], - c->quant[ch][band], ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], step_size, - c->adpcm_history[ch][band], c->subband[ch][band], c->adpcm_history[ch][band]+4, c->quantized[ch][band], - SUBBAND_SAMPLES, cb_to_level[-diff_peak_cb]); + c->quant[ch][band], + ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], + step_size, c->adpcm_history[ch][band], c->subband[ch][band], + c->adpcm_history[ch][band] + 4, c->quantized[ch][band], + SUBBAND_SAMPLES, c->cb_to_level[-diff_peak_cb]); } static void quantize_adpcm(DCAEncContext *c) @@ -731,21 +669,31 @@ static void quantize_pcm(DCAEncContext *c) { int sample, band, ch; - for (ch = 0; ch < c->fullband_channels; ch++) - for (band = 0; band < 32; band++) - if (c->prediction_mode[ch][band] == -1) - for (sample = 0; sample < SUBBAND_SAMPLES; sample++) - c->quantized[ch][band][sample] = quantize_value(c->subband[ch][band][sample], c->quant[ch][band]); + for (ch = 0; ch < c->fullband_channels; ch++) { + for (band = 0; band < 32; band++) { + if (c->prediction_mode[ch][band] == -1) { + for (sample = 0; sample < SUBBAND_SAMPLES; sample++) { + int32_t val = quantize_value(c->subband[ch][band][sample], + c->quant[ch][band]); + c->quantized[ch][band][sample] = val; + } + } + } + } } -static void accumulate_huff_bit_consumption(int abits, int32_t *quantized, uint32_t *result) +static void accumulate_huff_bit_consumption(int abits, int32_t *quantized, + uint32_t *result) { uint8_t sel, id = abits - 1; for (sel = 0; sel < ff_dca_quant_index_group_size[id]; sel++) - result[sel] += ff_dca_vlc_calc_quant_bits(quantized, SUBBAND_SAMPLES, sel, id); + result[sel] += ff_dca_vlc_calc_quant_bits(quantized, SUBBAND_SAMPLES, + sel, id); } -static uint32_t set_best_code(uint32_t vlc_bits[DCA_CODE_BOOKS][7], uint32_t clc_bits[DCA_CODE_BOOKS], int32_t res[DCA_CODE_BOOKS]) +static uint32_t set_best_code(uint32_t vlc_bits[DCA_CODE_BOOKS][7], + uint32_t clc_bits[DCA_CODE_BOOKS], + int32_t res[DCA_CODE_BOOKS]) { uint8_t i, sel; uint32_t best_sel_bits[DCA_CODE_BOOKS]; @@ -784,7 +732,8 @@ static uint32_t set_best_code(uint32_t vlc_bits[DCA_CODE_BOOKS][7], uint32_t clc return bits; } -static uint32_t set_best_abits_code(int abits[DCAENC_SUBBANDS], int bands, int32_t *res) +static uint32_t set_best_abits_code(int abits[DCAENC_SUBBANDS], int bands, + int32_t *res) { uint8_t i; uint32_t t; @@ -845,7 +794,8 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) ret &= ~(USED_26ABITS | USED_1ABITS); } } - c->consumed_bits += set_best_abits_code(c->abits[ch], 32, &c->bit_allocation_sel[ch]); + c->consumed_bits += set_best_abits_code(c->abits[ch], 32, + &c->bit_allocation_sel[ch]); } /* Recalc scale_factor each time to get bits consumption in case of Huffman coding. @@ -854,7 +804,7 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { if (c->prediction_mode[ch][band] == -1) { - c->scale_factor[ch][band] = calc_one_scale(c->peak_cb[ch][band], + c->scale_factor[ch][band] = calc_one_scale(c, c->peak_cb[ch][band], c->abits[ch][band], &c->quant[ch][band]); } @@ -868,7 +818,9 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { if (c->abits[ch][band] && c->abits[ch][band] <= DCA_CODE_BOOKS) { - accumulate_huff_bit_consumption(c->abits[ch][band], c->quantized[ch][band], huff_bit_count_accum[ch][c->abits[ch][band] - 1]); + accumulate_huff_bit_consumption(c->abits[ch][band], + c->quantized[ch][band], + huff_bit_count_accum[ch][c->abits[ch][band] - 1]); clc_bit_count_accum[ch][c->abits[ch][band] - 1] += bit_consumption[c->abits[ch][band]]; } else { bits_counter += bit_consumption[c->abits[ch][band]]; @@ -877,7 +829,9 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) } for (ch = 0; ch < c->fullband_channels; ch++) { - bits_counter += set_best_code(huff_bit_count_accum[ch], clc_bit_count_accum[ch], c->quant_index_sel[ch]); + bits_counter += set_best_code(huff_bit_count_accum[ch], + clc_bit_count_accum[ch], + c->quant_index_sel[ch]); } c->consumed_bits += bits_counter; @@ -954,7 +908,8 @@ static void fill_in_adpcm_bufer(DCAEncContext *c) step_size = get_step_size(c, ch, band); ff_dca_core_dequantize(c->adpcm_history[ch][band], - c->quantized[ch][band]+12, step_size, ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], 0, 4); + c->quantized[ch][band]+12, step_size, + ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], 0, 4); } else { AV_COPY128U(c->adpcm_history[ch][band], c->adpcm_history[ch][band]+4); } @@ -977,7 +932,7 @@ static void fill_in_adpcm_bufer(DCAEncContext *c) static void calc_lfe_scales(DCAEncContext *c) { if (c->lfe_channel) - c->lfe_scale_factor = calc_one_scale(c->lfe_peak_cb, 11, &c->lfe_quant); + c->lfe_scale_factor = calc_one_scale(c, c->lfe_peak_cb, 11, &c->lfe_quant); } static void put_frame_header(DCAEncContext *c) @@ -1118,7 +1073,8 @@ static void put_subframe_samples(DCAEncContext *c, int ss, int band, int ch) sel = c->quant_index_sel[ch][c->abits[ch][band] - 1]; // Huffman codes if (sel < ff_dca_quant_index_group_size[c->abits[ch][band] - 1]) { - ff_dca_vlc_enc_quant(&c->pb, &c->quantized[ch][band][ss * 8], 8, sel, c->abits[ch][band] - 1); + ff_dca_vlc_enc_quant(&c->pb, &c->quantized[ch][band][ss * 8], 8, + sel, c->abits[ch][band] - 1); return; } @@ -1171,7 +1127,8 @@ static void put_subframe(DCAEncContext *c, int subframe) put_bits(&c->pb, 5, c->abits[ch][band]); } } else { - ff_dca_vlc_enc_alloc(&c->pb, c->abits[ch], DCAENC_SUBBANDS, c->bit_allocation_sel[ch]); + ff_dca_vlc_enc_alloc(&c->pb, c->abits[ch], DCAENC_SUBBANDS, + c->bit_allocation_sel[ch]); } } @@ -1287,6 +1244,7 @@ AVCodec ff_dca_encoder = { .close = encode_close, .encode2 = encode_frame, .capabilities = AV_CODEC_CAP_EXPERIMENTAL, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, .supported_samplerates = sample_rates, diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 1337ffb52..f67b21475 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -40,6 +40,7 @@ #include "avcodec.h" #include "bytestream.h" #include "decode.h" +#include "hwaccel.h" #include "internal.h" #include "thread.h" @@ -369,8 +370,7 @@ static int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame) DecodeSimpleContext *ds = &avci->ds; AVPacket *pkt = ds->in_pkt; // copy to ensure we do not change pkt - AVPacket tmp; - int got_frame, actual_got_frame, did_split; + int got_frame, actual_got_frame; int ret; if (!pkt->data && !avci->draining) { @@ -390,31 +390,12 @@ static int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame) avctx->active_thread_type & FF_THREAD_FRAME)) return AVERROR_EOF; - tmp = *pkt; -#if FF_API_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - did_split = avci->compat_decode_partial_size ? - ff_packet_split_and_drop_side_data(&tmp) : - av_packet_split_side_data(&tmp); - - if (did_split) { - ret = extract_packet_props(avctx->internal, &tmp); - if (ret < 0) - return ret; - - ret = apply_param_change(avctx, &tmp); - if (ret < 0) - return ret; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - got_frame = 0; if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) { - ret = ff_thread_decode_frame(avctx, frame, &got_frame, &tmp); + ret = ff_thread_decode_frame(avctx, frame, &got_frame, pkt); } else { - ret = avctx->codec->decode(avctx, frame, &got_frame, &tmp); + 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; @@ -544,13 +525,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } } -#if FF_API_MERGE_SD - if (did_split) { - av_packet_free_side_data(&tmp); - if(ret == tmp.size) - ret = pkt->size; - } -#endif if (avctx->codec->type == AVMEDIA_TYPE_AUDIO && !avci->showed_multi_packet_warning && @@ -640,6 +614,28 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *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; } @@ -753,6 +749,11 @@ static int compat_decode(AVCodecContext *avctx, AVFrame *frame, 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; @@ -999,7 +1000,6 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, AVPacket *avpkt) { int i, ret = 0; - AVCodecInternal *avci = avctx->internal; if (!avpkt->data && avpkt->size) { av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n"); @@ -1016,29 +1016,9 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, get_subtitle_defaults(sub); if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size) { - AVPacket pkt_recoded; - AVPacket tmp = *avpkt; -#if FF_API_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - int did_split = avci->compat_decode_partial_size ? - ff_packet_split_and_drop_side_data(&tmp) : - av_packet_split_side_data(&tmp); - //apply_param_change(avctx, &tmp); + AVPacket pkt_recoded = *avpkt; - if (did_split) { - /* FFMIN() prevents overflow in case the packet wasn't allocated with - * proper padding. - * If the side data is smaller than the buffer padding size, the - * remaining bytes should have already been filled with zeros by the - * original packet allocation anyway. */ - memset(tmp.data + tmp.size, 0, - FFMIN(avpkt->size - tmp.size, AV_INPUT_BUFFER_PADDING_SIZE)); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - - pkt_recoded = tmp; - ret = recode_subtitle(avctx, &pkt_recoded, &tmp); + ret = recode_subtitle(avctx, &pkt_recoded, avpkt); if (ret < 0) { *got_sub_ptr = 0; } else { @@ -1087,7 +1067,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } } - if (tmp.data != pkt_recoded.data) { // did we recode? + 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; @@ -1096,14 +1076,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } -#if FF_API_MERGE_SD - if (did_split) { - av_packet_free_side_data(&tmp); - if(ret == tmp.size) - ret = avpkt->size; - } -#endif - if (*got_sub_ptr) avctx->frame_number++; } @@ -1111,84 +1083,228 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; } -static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt) +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *avctx, + const enum AVPixelFormat *fmt) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - return desc->flags & AV_PIX_FMT_FLAG_HWACCEL; -} + const AVPixFmtDescriptor *desc; + const AVCodecHWConfig *config; + int i, n; -enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat *fmt) -{ - while (*fmt != AV_PIX_FMT_NONE && is_hwaccel_pix_fmt(*fmt)) - ++fmt; - return fmt[0]; -} + // 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. -static AVHWAccel *find_hwaccel(enum AVCodecID codec_id, - enum AVPixelFormat pix_fmt) -{ - AVHWAccel *hwaccel = NULL; + // 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]; - while ((hwaccel = av_hwaccel_next(hwaccel))) - if (hwaccel->id == codec_id - && hwaccel->pix_fmt == pix_fmt) - return hwaccel; - return NULL; -} - -static int setup_hwaccel(AVCodecContext *avctx, - const enum AVPixelFormat fmt, - const char *name) -{ - AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt); - int ret = 0; - - if (!hwa) { - av_log(avctx, AV_LOG_ERROR, - "Could not find an AVHWAccel for the pixel format: %s", - name); - return AVERROR(ENOENT); + // 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]; + } } - if (hwa->capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL && + // 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; + + // Add an additional surface per thread is frame threading is enabled. + if (avctx->active_thread_type & FF_THREAD_FRAME) + frames_ctx->initial_pool_size += avctx->thread_count; + } + + 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) { + *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", - hwa->name); + hwaccel->name); return AVERROR_PATCHWELCOME; } - if (hwa->priv_data_size) { - avctx->internal->hwaccel_priv_data = av_mallocz(hwa->priv_data_size); + 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 = hwa; - if (hwa->init) { - ret = hwa->init(avctx); - if (ret < 0) { + 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 ret; + 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; - unsigned n = 0; - - while (fmt[n] != AV_PIX_FMT_NONE) - ++n; + 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); - avctx->sw_pix_fmt = fmt[n - 1]; - av_assert2(!is_hwaccel_pix_fmt(avctx->sw_pix_fmt)); + // 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) @@ -1197,48 +1313,108 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) memcpy(choices, fmt, (n + 1) * sizeof(*choices)); for (;;) { - if (avctx->hwaccel && avctx->hwaccel->uninit) - avctx->hwaccel->uninit(avctx); - av_freep(&avctx->internal->hwaccel_priv_data); - avctx->hwaccel = NULL; + // Remove the previous hwaccel, if there was one. + hwaccel_uninit(avctx); - av_buffer_unref(&avctx->hw_frames_ctx); - - ret = avctx->get_format(avctx, choices); - - desc = av_pix_fmt_desc_get(ret); - if (!desc) { + 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; } - if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) + 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; -#if FF_API_CAP_VDPAU - if (avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) - break; -#endif + } + av_log(avctx, AV_LOG_DEBUG, "Format %s chosen by get_format().\n", + desc->name); - if (avctx->hw_frames_ctx) { - AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - if (hw_frames_ctx->format != ret) { - av_log(avctx, AV_LOG_ERROR, "Format returned from get_buffer() " - "does not match the format of provided AVHWFramesContext\n"); - ret = AV_PIX_FMT_NONE; + 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); + break; } - if (!setup_hwaccel(avctx, ret, desc->name)) + 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; - /* Remove failed hwaccel from choices */ - for (n = 0; choices[n] != ret; n++) - av_assert0(choices[n] != AV_PIX_FMT_NONE); + 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; - do - choices[n] = choices[n + 1]; - while (choices[n++] != AV_PIX_FMT_NONE); + 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); @@ -1612,6 +1788,43 @@ static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) } } +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; @@ -1648,8 +1861,14 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) avctx->sw_pix_fmt = avctx->pix_fmt; ret = avctx->get_buffer2(avctx, frame, flags); - if (ret >= 0) - validate_avframe_allocation(avctx, frame); + 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 && @@ -1658,6 +1877,9 @@ end: frame->height = avctx->height; } + if (ret < 0) + av_frame_unref(frame); + return ret; } diff --git a/libavcodec/decode.h b/libavcodec/decode.h index c9630228d..15271c529 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -21,8 +21,38 @@ #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. * @@ -36,4 +66,14 @@ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt); 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/libavcodec/dfa.c b/libavcodec/dfa.c index 43dba2c8e..536040d65 100644 --- a/libavcodec/dfa.c +++ b/libavcodec/dfa.c @@ -149,6 +149,8 @@ static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height int mask = 0x10000, bitbuf = 0; int i, v, offset, count, segments; + if ((width | height) & 1) + return AVERROR_INVALIDDATA; segments = bytestream2_get_le16(gb); while (segments--) { if (bytestream2_get_bytes_left(gb) < 2) @@ -176,7 +178,7 @@ static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height return AVERROR_INVALIDDATA; frame += v; } else { - if (frame_end - frame < width + 4) + if (width < 4 || frame_end - frame < width + 4) return AVERROR_INVALIDDATA; frame[0] = frame[1] = frame[width] = frame[width + 1] = bytestream2_get_byte(gb); diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c index 027ce79a2..d5870d6c0 100644 --- a/libavcodec/dirac.c +++ b/libavcodec/dirac.c @@ -147,6 +147,7 @@ static int parse_source_parameters(AVDiracSeqHeader *dsh, GetBitContext *gb, 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 */ @@ -269,7 +270,10 @@ static int parse_source_parameters(AVDiracSeqHeader *dsh, GetBitContext *gb, return AVERROR_INVALIDDATA; dsh->pix_fmt = dirac_pix_fmt[dsh->chroma_format][dsh->pixel_range_index-2]; - avcodec_get_chroma_sub_sample(dsh->pix_fmt, &chroma_x_shift, &chroma_y_shift); + 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<> 1)) #define COMPOSE_DD97iH0(b0, b1, b2, b3, b4)\ - (b2 + ((int)(-b0 + 9U*b1 + 9U*b3 - b4 + 8) >> 4)) + (int)(((unsigned)(b2) + ((int)(-b0 + 9U*b1 + 9U*b3 - b4 + 8) >> 4))) #define COMPOSE_DD137iL0(b0, b1, b2, b3, b4)\ - (b2 - ((-b0 + 9*b1 + 9*b3 - b4 + 16) >> 5)) + (int)(((unsigned)(b2) - ((int)(-b0 + 9U*b1 + 9U*b3 - b4 + 16) >> 5))) #define COMPOSE_HAARiL0(b0, b1)\ - (b0 - ((b1 + 1) >> 1)) + ((int)(b0 - (unsigned)((int)(b1 + 1U) >> 1))) #define COMPOSE_HAARiH0(b0, b1)\ - (b0 + b1) + ((int)(b0 + (unsigned)(b1))) #define COMPOSE_FIDELITYiL0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\ - (b4 - ((int)(-8*(b0+(unsigned)b8) + 21*(b1+(unsigned)b7) - 46*(b2+(unsigned)b6) + 161*(b3+(unsigned)b5) + 128) >> 8)) + ((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)\ - (b4 + ((int)(-2*(b0+(unsigned)b8) + 10*(b1+(unsigned)b7) - 25*(b2+(unsigned)b6) + 81*(b3+(unsigned)b5) + 128) >> 8)) + ((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)\ - (b1 - ((int)(1817*(b0 + (unsigned)b2) + 2048) >> 12)) + ((unsigned)(b1) - ((int)(1817*(b0 + (unsigned)b2) + 2048) >> 12)) #define COMPOSE_DAUB97iH1(b0, b1, b2)\ - (b1 - ((int)( 113*(b0 + (unsigned)b2) + 64) >> 7)) + ((unsigned)(b1) - ((int)( 113*(b0 + (unsigned)b2) + 64) >> 7)) #define COMPOSE_DAUB97iL0(b0, b1, b2)\ - (b1 + ((int)( 217*(b0 + (unsigned)b2) + 2048) >> 12)) + ((unsigned)(b1) + ((int)( 217*(b0 + (unsigned)b2) + 2048) >> 12)) #define COMPOSE_DAUB97iH0(b0, b1, b2)\ - (b1 + ((int)(6497*(b0 + (unsigned)b2) + 2048) >> 12)) + ((unsigned)(b1) + ((int)(6497*(b0 + (unsigned)b2) + 2048) >> 12)) #endif /* AVCODEC_DWT_H */ diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index 0abb8b059..530e1c6ff 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -26,6 +26,7 @@ * @author Marco Gerards , David Conrad, Jordi Ortiz */ +#include "libavutil/pixdesc.h" #include "libavutil/thread.h" #include "avcodec.h" #include "get_bits.h" @@ -508,16 +509,16 @@ static inline void codeblock(DiracContext *s, SubBand *b, } if (s->codeblock_mode && !(s->old_delta_quant && blockcnt_one)) { - int quant = b->quant; + int quant; if (is_arith) - quant += dirac_get_arith_int(c, CTX_DELTA_Q_F, CTX_DELTA_Q_DATA); + quant = dirac_get_arith_int(c, CTX_DELTA_Q_F, CTX_DELTA_Q_DATA); else - quant += dirac_get_se_golomb(gb); - if (quant < 0) { + quant = dirac_get_se_golomb(gb); + if (quant > INT_MAX - b->quant || b->quant + quant < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid quant\n"); return; } - b->quant = quant; + b->quant += quant; } if (b->quant > (DIRAC_MAX_QUANT_INDEX - 1)) { @@ -1927,7 +1928,10 @@ static int get_buffer_with_edge(AVCodecContext *avctx, AVFrame *f, int flags) { int ret, i; int chroma_x_shift, chroma_y_shift; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &chroma_x_shift, &chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_x_shift, + &chroma_y_shift); + if (ret < 0) + return ret; f->width = avctx->width + 2 * EDGE_WIDTH; f->height = avctx->height + 2 * EDGE_WIDTH + 2; @@ -2126,7 +2130,11 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int s->pshift = s->bit_depth > 8; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, + &s->chroma_x_shift, + &s->chroma_y_shift); + if (ret < 0) + return ret; ret = alloc_sequence_buffers(s); if (ret < 0) diff --git a/libavcodec/diracdsp.c b/libavcodec/diracdsp.c index 8bc79b788..2dd56f83f 100644 --- a/libavcodec/diracdsp.c +++ b/libavcodec/diracdsp.c @@ -159,10 +159,10 @@ static void put_signed_rect_clamped_ ## PX ## bit_c(uint8_t *_dst, int dst_strid int32_t *src = (int32_t *)_src; \ for (y = 0; y < height; y++) { \ for (x = 0; x < width; x+=4) { \ - dst[x ] = av_clip_uintp2(src[x ] + (1 << (PX - 1)), PX); \ - dst[x+1] = av_clip_uintp2(src[x+1] + (1 << (PX - 1)), PX); \ - dst[x+2] = av_clip_uintp2(src[x+2] + (1 << (PX - 1)), PX); \ - dst[x+3] = av_clip_uintp2(src[x+3] + (1 << (PX - 1)), PX); \ + dst[x ] = av_clip_uintp2(src[x ] + (1U << (PX - 1)), PX); \ + dst[x+1] = av_clip_uintp2(src[x+1] + (1U << (PX - 1)), PX); \ + dst[x+2] = av_clip_uintp2(src[x+2] + (1U << (PX - 1)), PX); \ + dst[x+3] = av_clip_uintp2(src[x+3] + (1U << (PX - 1)), PX); \ } \ dst += dst_stride >> 1; \ src += src_stride >> 2; \ diff --git a/libavcodec/dnxhddata.c b/libavcodec/dnxhddata.c index 4462df3c2..e9dd29ce4 100644 --- a/libavcodec/dnxhddata.c +++ b/libavcodec/dnxhddata.c @@ -939,96 +939,84 @@ const CIDEntry ff_dnxhd_cid_table[] = { dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 175, 185, 365, 440 }, - { { 24000, 1001 }, { 25, 1 }, { 50, 1 }, { 60000, 1001 } } }, + { 175, 185, 365, 440 } }, { 1237, 1920, 1080, 606208, 606208, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 115, 120, 145, 240, 290 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 115, 120, 145, 240, 290 } }, { 1238, 1920, 1080, 917504, 917504, 0, 4, 8, 4, dnxhd_1238_luma_weight, dnxhd_1238_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1238_run, - { 175, 185, 220, 365, 440 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 175, 185, 220, 365, 440 } }, { 1241, 1920, 1080, 917504, 458752, DNXHD_INTERLACED, 6, 10, 4, dnxhd_1241_luma_weight, dnxhd_1241_chroma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 185, 220 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 185, 220 } }, { 1242, 1920, 1080, 606208, 303104, DNXHD_INTERLACED, 4, 8, 3, dnxhd_1242_luma_weight, dnxhd_1242_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 120, 145 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 120, 145 } }, { 1243, 1920, 1080, 917504, 458752, DNXHD_INTERLACED, 4, 8, 4, dnxhd_1243_luma_weight, dnxhd_1243_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1238_run, - { 185, 220 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 185, 220 } }, { 1244, 1440, 1080, 606208, 303104, DNXHD_INTERLACED, 4, 8, 3, dnxhd_1260_luma_weight, dnxhd_1260_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 120, 145 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 120, 145 } }, { 1250, 1280, 720, 458752, 458752, 0, 6, 10, 4, dnxhd_1250_luma_weight, dnxhd_1250_chroma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1250_ac_codes, dnxhd_1250_ac_bits, dnxhd_1250_ac_info, dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run, - { 90, 90, 180, 220 }, - { { 24000, 1001 }, { 25, 1 }, { 50, 1 }, { 60000, 1001 } } }, + { 90, 180, 220 } }, { 1251, 1280, 720, 458752, 458752, 0, 4, 8, 4, dnxhd_1251_luma_weight, dnxhd_1251_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1251_ac_codes, dnxhd_1251_ac_bits, dnxhd_1251_ac_info, dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run, - { 90, 90, 110, 180, 220 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 90, 110, 180, 220 } }, { 1252, 1280, 720, 303104, 303104, 0, 4, 8, 5, dnxhd_1252_luma_weight, dnxhd_1252_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1252_ac_codes, dnxhd_1252_ac_bits, dnxhd_1252_ac_info, dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run, - { 60, 60, 75, 120, 145 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 60, 75, 120, 145 } }, { 1253, 1920, 1080, 188416, 188416, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 36, 36, 45, 75, 90 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 36, 45, 75, 90 } }, { 1256, 1920, 1080, 1835008, 1835008, DNXHD_444, 6, 10, 4, dnxhd_1235_luma_weight, dnxhd_1235_luma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 350, 390, 440, 730, 880 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 350, 390, 440, 730, 880 } }, { 1258, 960, 720, 212992, 212992, 0, 4, 8, 5, dnxhd_1252_luma_weight, dnxhd_1252_chroma_weight, @@ -1056,35 +1044,35 @@ const CIDEntry ff_dnxhd_cid_table[] = { dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 0 }, { { 0 } }, { 57344, 255} }, + { 0 }, { 57344, 255} }, { 1271, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 6, DNXHD_VARIABLE, 4, dnxhd_1241_luma_weight, dnxhd_1241_chroma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 0 }, { { 0 } }, { 28672, 255} }, + { 0 }, { 28672, 255} }, { 1272, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 4, 8, 4, dnxhd_1238_luma_weight, dnxhd_1238_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1238_run, - { 0 }, { { 0 } }, { 28672, 255} }, + { 0 }, { 28672, 255} }, { 1273, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 0 }, { { 0 } }, { 18944, 255} }, + { 0 }, { 18944, 255} }, { 1274, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 0 }, { { 0 } }, { 5888, 255} }, + { 0 }, { 5888, 255} }, }; int ff_dnxhd_get_cid_table(int cid) @@ -1112,13 +1100,6 @@ int avpriv_dnxhd_get_interlaced(int cid) return ff_dnxhd_cid_table[i].flags & DNXHD_INTERLACED ? 1 : 0; } -#if LIBAVCODEC_VERSION_MAJOR < 58 -uint64_t avpriv_dnxhd_parse_header_prefix(const uint8_t *buf) -{ - return ff_dnxhd_parse_header_prefix(buf); -} -#endif - static int dnxhd_find_hr_cid(AVCodecContext *avctx) { switch (avctx->profile) { @@ -1175,9 +1156,9 @@ void ff_dnxhd_print_profiles(AVCodecContext *avctx, int loglevel) if (!cid->bit_rates[j]) break; - av_log(avctx, loglevel, "Frame size: %dx%d%c; bitrate: %dMbps; pixel format: %s; framerate: %d/%d\n", + av_log(avctx, loglevel, "Frame size: %dx%d%c; bitrate: %dMbps; pixel format: %s\n", cid->width, cid->height, cid->flags & DNXHD_INTERLACED ? 'i' : 'p', cid->bit_rates[j], - cid->bit_depth == 10 ? "yuv422p10" : "yuv422p", cid->frame_rates[j].num, cid->frame_rates[j].den); + cid->flags & DNXHD_444 ? "yuv444p10, gbrp10" : cid->bit_depth == 10 ? "yuv422p10" : "yuv422p"); } } } diff --git a/libavcodec/dnxhddata.h b/libavcodec/dnxhddata.h index c96c5e8f6..f80ce18f3 100644 --- a/libavcodec/dnxhddata.h +++ b/libavcodec/dnxhddata.h @@ -55,7 +55,6 @@ typedef struct CIDEntry { const uint16_t *run_codes; const uint8_t *run_bits, *run; int bit_rates[5]; ///< Helper to choose variants, rounded to nearest 5Mb/s - AVRational frame_rates[5]; AVRational packet_scale; } CIDEntry; @@ -106,8 +105,5 @@ static av_always_inline int ff_dnxhd_get_hr_frame_size(int cid, int w, int h) int avpriv_dnxhd_get_frame_size(int cid); int avpriv_dnxhd_get_interlaced(int cid); -#if LIBAVCODEC_VERSION_MAJOR < 58 -attribute_deprecated -uint64_t avpriv_dnxhd_parse_header_prefix(const uint8_t *buf); -#endif + #endif /* AVCODEC_DNXHDDATA_H */ diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c index f46e41a45..11d0bf424 100644 --- a/libavcodec/dnxhddec.c +++ b/libavcodec/dnxhddec.c @@ -93,7 +93,9 @@ static av_cold int dnxhd_decode_init(AVCodecContext *avctx) ctx->avctx = avctx; ctx->cid = -1; - avctx->colorspace = AVCOL_SPC_BT709; + if (avctx->colorspace == AVCOL_SPC_UNSPECIFIED) { + avctx->colorspace = AVCOL_SPC_BT709; + } avctx->coded_width = FFALIGN(avctx->width, 16); avctx->coded_height = FFALIGN(avctx->height, 16); @@ -381,6 +383,10 @@ static av_always_inline int dnxhd_decode_dct_block(const DNXHDContext *ctx, UPDATE_CACHE(bs, &row->gb); GET_VLC(len, bs, &row->gb, ctx->dc_vlc.table, DNXHD_DC_VLC_BITS, 1); + if (len < 0) { + ret = len; + goto error; + } if (len) { level = GET_CACHE(bs, &row->gb); LAST_SKIP_BITS(bs, &row->gb, len); @@ -434,7 +440,7 @@ static av_always_inline int dnxhd_decode_dct_block(const DNXHDContext *ctx, GET_VLC(index1, bs, &row->gb, ctx->ac_vlc.table, DNXHD_VLC_BITS, 2); } - +error: CLOSE_READER(bs, &row->gb); return ret; } diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 0d80381a2..86e71ca8b 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -490,12 +490,6 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) else ctx->data_offset = 0x280; -#if FF_API_QUANT_BIAS -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS) - ctx->intra_quant_bias = avctx->intra_quant_bias; -FF_ENABLE_DEPRECATION_WARNINGS -#endif // XXX tune lbias/cbias if ((ret = dnxhd_init_qmat(ctx, ctx->intra_quant_bias, 0)) < 0) return ret; diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c index 3cdbade99..8cce702a9 100644 --- a/libavcodec/dvbsub.c +++ b/libavcodec/dvbsub.c @@ -239,9 +239,9 @@ static void dvb_encode_rle8(uint8_t **pq, x += len; } /* end of line */ - // 00000000 00000000 end of 8-bit/pixel_code_string - *q++ = 0x00; + // 00000000 end of 8-bit/pixel_code_string *q++ = 0x00; + *q++ = 0xf0; bitmap += linesize; } *pq = q; @@ -342,6 +342,9 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s, } else if (h->rects[region_id]->nb_colors <= 16) { /* 4 bpp, standard encoding */ bpp_index = 1; + } else if (h->rects[region_id]->nb_colors <= 256) { + /* 8 bpp, standard encoding */ + bpp_index = 2; } else { return -1; } diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index b68310964..a657b1d3d 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -96,6 +96,9 @@ typedef struct DVBSubRegion { int clut; int bgcolor; + uint8_t computed_clut[4*256]; + int has_computed_clut; + uint8_t *pbuf; int buf_size; int dirty; @@ -647,14 +650,14 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, return pixels_read; } -static void compute_default_clut(AVSubtitleRect *rect, int w, int h) +static void compute_default_clut(uint8_t *clut, AVSubtitleRect *rect, int w, int h) { uint8_t list[256] = {0}; uint8_t list_inv[256]; int counttab[256] = {0}; int count, i, x, y; - -#define V(x,y) rect->data[0][(x) + (y)*rect->linesize[0]] + ptrdiff_t stride = rect->linesize[0]; +#define V(x,y) rect->data[0][(x) + (y)*stride] for (y = 0; ydata[0][(x) + (y)*rect->linesize[0]] ] +#define L(x,y) list[d[(x) + (y)*stride]] for (i = 0; i<256; i++) { int scoretab[256] = {0}; @@ -673,20 +676,24 @@ static void compute_default_clut(AVSubtitleRect *rect, int w, int h) int bestv = 0; for (y = 0; ydata[0][x + y*rect->linesize[0]]; + uint8_t *d = &rect->data[0][x + y*stride]; + int v = *d; int l_m = list[v]; - int l_l = x ? L(x-1, y) : 1; - int l_r = x+1 bestscore) { bestscore = score; - bestv = v; + bestv = x; } } } @@ -699,7 +706,7 @@ static void compute_default_clut(AVSubtitleRect *rect, int w, int h) count = FFMAX(i - 1, 1); for (i--; i>=0; i--) { int v = i*255/count; - AV_WN32(rect->data[1] + 4*list_inv[i], RGBA(v/2,v,v/2,v)); + AV_WN32(clut + 4*list_inv[i], RGBA(v/2,v,v/2,v)); } } @@ -749,8 +756,13 @@ static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou goto fail; } - for(i=0; inum_rects; i++) + for (i = 0; i < sub->num_rects; i++) { sub->rects[i] = av_mallocz(sizeof(*sub->rects[i])); + if (!sub->rects[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } i = 0; @@ -805,8 +817,14 @@ static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou memcpy(rect->data[0], region->pbuf, region->buf_size); - if ((clut == &default_clut && ctx->compute_clut == -1) || ctx->compute_clut == 1) - compute_default_clut(rect, rect->w, rect->h); + if ((clut == &default_clut && ctx->compute_clut == -1) || ctx->compute_clut == 1) { + if (!region->has_computed_clut) { + compute_default_clut(region->computed_clut, rect, rect->w, rect->h); + region->has_computed_clut = 1; + } + + memcpy(rect->data[1], region->computed_clut, sizeof(region->computed_clut)); + } #if FF_API_AVPICTURE FF_DISABLE_DEPRECATION_WARNINGS @@ -955,6 +973,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis } } + region->has_computed_clut = 0; } static int dvbsub_parse_object_segment(AVCodecContext *avctx, diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index afcd361ef..6f294703f 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -29,6 +29,7 @@ #include "libavutil/time.h" #include "avcodec.h" +#include "decode.h" #include "dxva2_internal.h" /* define all the GUIDs used directly here, @@ -576,14 +577,20 @@ static void ff_dxva2_unlock(AVCodecContext *avctx) #endif } -// This must work before the decoder is created. -// This somehow needs to be exported to the user. -static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frames_ctx) +int ff_dxva2_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) { - FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)hw_frames_ctx->data; + AVHWDeviceContext *device_ctx = frames_ctx->device_ctx; int surface_alignment, num_surfaces; - frames_ctx->format = sctx->pix_fmt; + if (device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { + frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; + } else if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + frames_ctx->format = AV_PIX_FMT_D3D11; + } else { + return AVERROR(EINVAL); + } /* decoding MPEG-2 requires additional alignment on some Intel GPUs, but it causes issues for H.264 on certain AMD GPUs..... */ @@ -596,8 +603,8 @@ static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frame else surface_alignment = 16; - /* 4 base work surfaces */ - num_surfaces = 4; + /* 1 base work surface */ + num_surfaces = 1; /* add surfaces based on number of possible refs */ if (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_HEVC) @@ -633,12 +640,16 @@ static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frame frames_hwctx->BindFlags |= D3D11_BIND_DECODER; } #endif + + return 0; } int ff_dxva2_decode_init(AVCodecContext *avctx) { FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); - AVHWFramesContext *frames_ctx = NULL; + AVHWFramesContext *frames_ctx; + enum AVHWDeviceType dev_type = avctx->hwaccel->pix_fmt == AV_PIX_FMT_DXVA2_VLD + ? AV_HWDEVICE_TYPE_DXVA2 : AV_HWDEVICE_TYPE_D3D11VA; int ret = 0; // Old API. @@ -648,32 +659,14 @@ int ff_dxva2_decode_init(AVCodecContext *avctx) // (avctx->pix_fmt is not updated yet at this point) sctx->pix_fmt = avctx->hwaccel->pix_fmt; - if (!avctx->hw_frames_ctx && !avctx->hw_device_ctx) { - av_log(avctx, AV_LOG_ERROR, "Either a hw_frames_ctx or a hw_device_ctx needs to be set for hardware decoding.\n"); - return AVERROR(EINVAL); - } - - if (avctx->hw_frames_ctx) { - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - } else { - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); - if (!avctx->hw_frames_ctx) - return AVERROR(ENOMEM); - - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - - dxva_adjust_hwframes(avctx, frames_ctx); - - ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (ret < 0) - goto fail; - } + ret = ff_decode_get_hw_frames_ctx(avctx, dev_type); + if (ret < 0) + return ret; + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; sctx->device_ctx = frames_ctx->device_ctx; - if (frames_ctx->format != sctx->pix_fmt || - !((sctx->pix_fmt == AV_PIX_FMT_D3D11 && CONFIG_D3D11VA) || - (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && CONFIG_DXVA2))) { + if (frames_ctx->format != sctx->pix_fmt) { av_log(avctx, AV_LOG_ERROR, "Invalid pixfmt for hwaccel!\n"); ret = AVERROR(EINVAL); goto fail; diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index e3a3f7866..a4278c80b 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -518,7 +518,7 @@ static int dxva2_h264_end_frame(AVCodecContext *avctx) } #if CONFIG_H264_DXVA2_HWACCEL -AVHWAccel ff_h264_dxva2_hwaccel = { +const AVHWAccel ff_h264_dxva2_hwaccel = { .name = "h264_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -528,13 +528,14 @@ AVHWAccel ff_h264_dxva2_hwaccel = { .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_H264_D3D11VA_HWACCEL -AVHWAccel ff_h264_d3d11va_hwaccel = { +const AVHWAccel ff_h264_d3d11va_hwaccel = { .name = "h264_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -544,13 +545,14 @@ AVHWAccel ff_h264_d3d11va_hwaccel = { .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_H264_D3D11VA2_HWACCEL -AVHWAccel ff_h264_d3d11va2_hwaccel = { +const AVHWAccel ff_h264_d3d11va2_hwaccel = { .name = "h264_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -560,6 +562,7 @@ AVHWAccel ff_h264_d3d11va2_hwaccel = { .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c index 88f887a1b..0ae07d304 100644 --- a/libavcodec/dxva2_hevc.c +++ b/libavcodec/dxva2_hevc.c @@ -422,7 +422,7 @@ static int dxva2_hevc_end_frame(AVCodecContext *avctx) } #if CONFIG_HEVC_DXVA2_HWACCEL -AVHWAccel ff_hevc_dxva2_hwaccel = { +const AVHWAccel ff_hevc_dxva2_hwaccel = { .name = "hevc_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -432,13 +432,14 @@ AVHWAccel ff_hevc_dxva2_hwaccel = { .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_HEVC_D3D11VA_HWACCEL -AVHWAccel ff_hevc_d3d11va_hwaccel = { +const AVHWAccel ff_hevc_d3d11va_hwaccel = { .name = "hevc_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -448,13 +449,14 @@ AVHWAccel ff_hevc_d3d11va_hwaccel = { .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_HEVC_D3D11VA2_HWACCEL -AVHWAccel ff_hevc_d3d11va2_hwaccel = { +const AVHWAccel ff_hevc_d3d11va2_hwaccel = { .name = "hevc_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -464,6 +466,7 @@ AVHWAccel ff_hevc_d3d11va2_hwaccel = { .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h index 352a9db1a..8bb334409 100644 --- a/libavcodec/dxva2_internal.h +++ b/libavcodec/dxva2_internal.h @@ -156,6 +156,9 @@ int ff_dxva2_decode_init(AVCodecContext *avctx); int ff_dxva2_decode_uninit(AVCodecContext *avctx); +int ff_dxva2_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx); + int ff_dxva2_is_d3d11(const AVCodecContext *avctx); #endif /* AVCODEC_DXVA2_INTERNAL_H */ diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c index b7c69378f..a57778b42 100644 --- a/libavcodec/dxva2_mpeg2.c +++ b/libavcodec/dxva2_mpeg2.c @@ -317,7 +317,7 @@ static int dxva2_mpeg2_end_frame(AVCodecContext *avctx) } #if CONFIG_MPEG2_DXVA2_HWACCEL -AVHWAccel ff_mpeg2_dxva2_hwaccel = { +const AVHWAccel ff_mpeg2_dxva2_hwaccel = { .name = "mpeg2_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -327,13 +327,14 @@ AVHWAccel ff_mpeg2_dxva2_hwaccel = { .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_MPEG2_D3D11VA_HWACCEL -AVHWAccel ff_mpeg2_d3d11va_hwaccel = { +const AVHWAccel ff_mpeg2_d3d11va_hwaccel = { .name = "mpeg2_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -343,13 +344,14 @@ AVHWAccel ff_mpeg2_d3d11va_hwaccel = { .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_MPEG2_D3D11VA2_HWACCEL -AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { +const AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { .name = "mpeg2_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -359,6 +361,7 @@ AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c index e5353cddd..f22c73cd1 100644 --- a/libavcodec/dxva2_vc1.c +++ b/libavcodec/dxva2_vc1.c @@ -378,7 +378,7 @@ static int dxva2_vc1_end_frame(AVCodecContext *avctx) } #if CONFIG_WMV3_DXVA2_HWACCEL -AVHWAccel ff_wmv3_dxva2_hwaccel = { +const AVHWAccel ff_wmv3_dxva2_hwaccel = { .name = "wmv3_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -388,13 +388,14 @@ AVHWAccel ff_wmv3_dxva2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VC1_DXVA2_HWACCEL -AVHWAccel ff_vc1_dxva2_hwaccel = { +const AVHWAccel ff_vc1_dxva2_hwaccel = { .name = "vc1_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -404,13 +405,14 @@ AVHWAccel ff_vc1_dxva2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_WMV3_D3D11VA_HWACCEL -AVHWAccel ff_wmv3_d3d11va_hwaccel = { +const AVHWAccel ff_wmv3_d3d11va_hwaccel = { .name = "wmv3_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -420,13 +422,14 @@ AVHWAccel ff_wmv3_d3d11va_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_WMV3_D3D11VA2_HWACCEL -AVHWAccel ff_wmv3_d3d11va2_hwaccel = { +const AVHWAccel ff_wmv3_d3d11va2_hwaccel = { .name = "wmv3_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -436,13 +439,14 @@ AVHWAccel ff_wmv3_d3d11va2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VC1_D3D11VA_HWACCEL -AVHWAccel ff_vc1_d3d11va_hwaccel = { +const AVHWAccel ff_vc1_d3d11va_hwaccel = { .name = "vc1_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -452,13 +456,14 @@ AVHWAccel ff_vc1_d3d11va_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VC1_D3D11VA2_HWACCEL -AVHWAccel ff_vc1_d3d11va2_hwaccel = { +const AVHWAccel ff_vc1_d3d11va2_hwaccel = { .name = "vc1_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c index 6d87fdd9f..5a5b22642 100644 --- a/libavcodec/dxva2_vp9.c +++ b/libavcodec/dxva2_vp9.c @@ -309,7 +309,7 @@ static int dxva2_vp9_end_frame(AVCodecContext *avctx) } #if CONFIG_VP9_DXVA2_HWACCEL -AVHWAccel ff_vp9_dxva2_hwaccel = { +const AVHWAccel ff_vp9_dxva2_hwaccel = { .name = "vp9_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -319,13 +319,14 @@ AVHWAccel ff_vp9_dxva2_hwaccel = { .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VP9_D3D11VA_HWACCEL -AVHWAccel ff_vp9_d3d11va_hwaccel = { +const AVHWAccel ff_vp9_d3d11va_hwaccel = { .name = "vp9_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -335,13 +336,14 @@ AVHWAccel ff_vp9_d3d11va_hwaccel = { .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VP9_D3D11VA2_HWACCEL -AVHWAccel ff_vp9_d3d11va2_hwaccel = { +const AVHWAccel ff_vp9_d3d11va2_hwaccel = { .name = "vp9_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -351,6 +353,7 @@ AVHWAccel ff_vp9_d3d11va2_hwaccel = { .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index c971879b2..6f6309f17 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -48,7 +48,6 @@ #include "internal.h" #include "aac_ac3_parser.h" #include "ac3.h" -#include "ac3_parser.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "eac3_data.h" diff --git a/libavcodec/encode.c b/libavcodec/encode.c index c961dbace..71b1b14af 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -257,10 +257,6 @@ end: av_frame_free(&padded_frame); av_free(extended_frame); -#if FF_API_AUDIOENC_DELAY - avctx->delay = avctx->initial_padding; -#endif - return ret; } diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 5364940e9..55f77961c 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -27,7 +27,6 @@ #include -#include "libavutil/atomic.h" #include "libavutil/internal.h" #include "avcodec.h" #include "error_resilience.h" @@ -807,16 +806,13 @@ void ff_er_frame_start(ERContext *s) memset(s->error_status_table, ER_MB_ERROR | VP_START | ER_MB_END, s->mb_stride * s->mb_height * sizeof(uint8_t)); - s->error_count = 3 * s->mb_num; + 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 || -#if FF_API_CAP_VDPAU - s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU || -#endif !s->cur_pic.f || s->cur_pic.field_picture ) @@ -855,20 +851,20 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, mask &= ~VP_START; if (status & (ER_AC_ERROR | ER_AC_END)) { mask &= ~(ER_AC_ERROR | ER_AC_END); - avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1); + 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); - avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1); + 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); - avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); } if (status & ER_MB_ERROR) { s->error_occurred = 1; - avpriv_atomic_int_set(&s->error_count, INT_MAX); + atomic_store(&s->error_count, INT_MAX); } if (mask == ~0x7F) { @@ -881,7 +877,7 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, } if (end_i == s->mb_num) - avpriv_atomic_int_set(&s->error_count, INT_MAX); + atomic_store(&s->error_count, INT_MAX); else { s->error_status_table[end_xy] &= mask; s->error_status_table[end_xy] |= status; @@ -896,7 +892,7 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, prev_status &= ~ VP_START; if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) { s->error_occurred = 1; - avpriv_atomic_int_set(&s->error_count, INT_MAX); + atomic_store(&s->error_count, INT_MAX); } } } @@ -913,10 +909,10 @@ void ff_er_frame_end(ERContext *s) /* We do not support ER of field pictures yet, * though it should not crash if enabled. */ - if (!s->avctx->error_concealment || s->error_count == 0 || + if (!s->avctx->error_concealment || !atomic_load(&s->error_count) || s->avctx->lowres || !er_supported(s) || - s->error_count == 3 * s->mb_width * + atomic_load(&s->error_count) == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom)) { return; } @@ -930,7 +926,7 @@ void ff_er_frame_end(ERContext *s) if ( mb_x == s->mb_width && s->avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && (FFALIGN(s->avctx->height, 16)&16) - && s->error_count == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom + 1) + && 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; diff --git a/libavcodec/error_resilience.h b/libavcodec/error_resilience.h index 27c200869..664a76565 100644 --- a/libavcodec/error_resilience.h +++ b/libavcodec/error_resilience.h @@ -20,6 +20,7 @@ #define AVCODEC_ERROR_RESILIENCE_H #include +#include #include "avcodec.h" #include "me_cmp.h" @@ -60,7 +61,7 @@ typedef struct ERContext { ptrdiff_t mb_stride; ptrdiff_t b8_stride; - volatile int error_count; + atomic_int error_count; int error_occurred; uint8_t *error_status_table; uint8_t *er_temp_buffer; diff --git a/libavcodec/exif.c b/libavcodec/exif.c index 07ce1741c..2874772db 100644 --- a/libavcodec/exif.c +++ b/libavcodec/exif.c @@ -92,7 +92,7 @@ static int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le, // store metadata or proceed with next IFD ret = ff_tis_ifd(id); if (ret) { - ret = avpriv_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata); + ret = ff_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata); } else { const char *name = exif_get_tag_name(id); char *use_name = (char*) name; @@ -119,8 +119,8 @@ static int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le, } -int avpriv_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, - int depth, AVDictionary **metadata) +int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, + int le, int depth, AVDictionary **metadata) { int i, ret; int entries; @@ -140,3 +140,13 @@ int avpriv_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, // return next IDF offset or 0x000000000 or a value < 0 for failure return ff_tget_long(gbytes, le); } + +int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, + int le, int depth, AVDictionary **metadata) +{ + GetByteContext gb; + + bytestream2_init(&gb, buf, size); + + return ff_exif_decode_ifd(logctx, &gb, le, depth, metadata); +} diff --git a/libavcodec/exif.h b/libavcodec/exif.h index 5f09208b9..05af756c4 100644 --- a/libavcodec/exif.h +++ b/libavcodec/exif.h @@ -164,7 +164,10 @@ static const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification: /** Recursively decodes all IFD's and * adds included TAGS into the metadata dictionary. */ -int avpriv_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, - int depth, AVDictionary **metadata); +int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, + int le, int depth, AVDictionary **metadata); + +int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, + int depth, AVDictionary **metadata); #endif /* AVCODEC_EXIF_H */ diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 0b755db3c..454dc74cf 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -855,7 +855,7 @@ static int pxr24_uncompress(EXRContext *s, const uint8_t *src, in = ptr[2] + td->xsize; for (j = 0; j < td->xsize; ++j) { - uint32_t diff = (*(ptr[0]++) << 24) | + uint32_t diff = ((unsigned)*(ptr[0]++) << 24) | (*(ptr[1]++) << 16) | (*(ptr[2]++) << 8); pixel += diff; @@ -1051,7 +1051,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, line_offset = AV_RL64(s->gb.buffer + jobnr * 8); if (s->is_tile) { - if (line_offset > buf_size - 20) + if (buf_size < 20 || line_offset > buf_size - 20) return AVERROR_INVALIDDATA; src = buf + line_offset + 20; @@ -1062,7 +1062,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, tile_level_y = AV_RL32(src - 8); data_size = AV_RL32(src - 4); - if (data_size <= 0 || data_size > buf_size) + if (data_size <= 0 || data_size > buf_size - line_offset - 20) return AVERROR_INVALIDDATA; if (tile_level_x || tile_level_y) { /* tile level, is not the full res level */ @@ -1095,7 +1095,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, td->channel_line_size = td->xsize * s->current_channel_offset;/* uncompress size of one line */ uncompressed_size = td->channel_line_size * (uint64_t)td->ysize;/* uncompress size of the block */ } else { - if (line_offset > buf_size - 8) + if (buf_size < 8 || line_offset > buf_size - 8) return AVERROR_INVALIDDATA; src = buf + line_offset + 8; @@ -1105,7 +1105,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, return AVERROR_INVALIDDATA; data_size = AV_RL32(src - 4); - if (data_size <= 0 || data_size > buf_size) + if (data_size <= 0 || data_size > buf_size - line_offset - 8) return AVERROR_INVALIDDATA; td->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1); /* s->ydelta - line ?? */ diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c index ed6509c68..d40907a67 100644 --- a/libavcodec/extract_extradata_bsf.c +++ b/libavcodec/extract_extradata_bsf.c @@ -78,7 +78,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, ret = ff_h2645_packet_split(&h2645_pkt, pkt->data, pkt->size, ctx, 0, 0, ctx->par_in->codec_id, 1); if (ret < 0) - return ret; + goto fail; for (i = 0; i < h2645_pkt.nb_nals; i++) { H2645NAL *nal = &h2645_pkt.nals[i]; diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index c9a885ebf..c0c1558ff 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -630,10 +630,6 @@ FF_ENABLE_DEPRECATION_WARNINGS s->bits_per_raw_sample = 16; s->use32bit = 1; s->version = FFMAX(s->version, 1); - if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "16bit RGB is experimental and under development, only use it for experiments\n"); - return AVERROR_INVALIDDATA; - } break; case AV_PIX_FMT_0RGB32: s->colorspace = 1; @@ -754,7 +750,10 @@ FF_ENABLE_DEPRECATION_WARNINGS if (!s->chroma_planes && s->version > 3) s->plane_count--; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); + ret = av_pix_fmt_get_chroma_sub_sample (avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); + if (ret) + return ret; + s->picture_number = 0; if (avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) { diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index 581c73efc..c8eb45604 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -220,20 +220,27 @@ static int get_metadata_size(const uint8_t *buf, int buf_size) static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) { + GetBitContext gb = s->gb; int i, tmp, partition, method_type, rice_order; int rice_bits, rice_esc; int samples; - method_type = get_bits(&s->gb, 2); + method_type = get_bits(&gb, 2); + rice_order = get_bits(&gb, 4); + + samples = s->blocksize >> rice_order; + rice_bits = 4 + method_type; + rice_esc = (1 << rice_bits) - 1; + + decoded += pred_order; + i = pred_order; + if (method_type > 1) { av_log(s->avctx, AV_LOG_ERROR, "illegal residual coding method %d\n", method_type); return AVERROR_INVALIDDATA; } - rice_order = get_bits(&s->gb, 4); - - samples= s->blocksize >> rice_order; if (samples << rice_order != s->blocksize) { av_log(s->avctx, AV_LOG_ERROR, "invalid rice order: %i blocksize %i\n", rice_order, s->blocksize); @@ -246,21 +253,16 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) return AVERROR_INVALIDDATA; } - rice_bits = 4 + method_type; - rice_esc = (1 << rice_bits) - 1; - - decoded += pred_order; - i= pred_order; for (partition = 0; partition < (1 << rice_order); partition++) { - tmp = get_bits(&s->gb, rice_bits); + tmp = get_bits(&gb, rice_bits); if (tmp == rice_esc) { - tmp = get_bits(&s->gb, 5); + tmp = get_bits(&gb, 5); for (; i < samples; i++) - *decoded++ = get_sbits_long(&s->gb, tmp); + *decoded++ = get_sbits_long(&gb, tmp); } else { int real_limit = tmp ? (INT_MAX >> tmp) + 2 : INT_MAX; for (; i < samples; i++) { - int v = get_sr_golomb_flac(&s->gb, tmp, real_limit, 0); + int v = get_sr_golomb_flac(&gb, tmp, real_limit, 0); if (v == 0x80000000){ av_log(s->avctx, AV_LOG_ERROR, "invalid residual\n"); return AVERROR_INVALIDDATA; @@ -272,6 +274,8 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) i= 0; } + s->gb = gb; + return 0; } @@ -298,7 +302,7 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded, if (pred_order > 2) c = b - decoded[pred_order-2] + decoded[pred_order-3]; if (pred_order > 3) - d = c - decoded[pred_order-2] + 2*decoded[pred_order-3] - decoded[pred_order-4]; + d = c - decoded[pred_order-2] + 2U*decoded[pred_order-3] - decoded[pred_order-4]; switch (pred_order) { case 0: @@ -456,7 +460,7 @@ static inline int decode_subframe(FLACContext *s, int channel) return AVERROR_INVALIDDATA; } - if (wasted) { + if (wasted && wasted < 32) { int i; for (i = 0; i < s->blocksize; i++) decoded[i] = (unsigned)decoded[i] << wasted; diff --git a/libavcodec/fmvc.c b/libavcodec/fmvc.c index 74e9bdd8a..a06b90c6f 100644 --- a/libavcodec/fmvc.c +++ b/libavcodec/fmvc.c @@ -44,11 +44,11 @@ typedef struct FMVCContext { size_t buffer_size; uint8_t *pbuffer; size_t pbuffer_size; - int stride; + ptrdiff_t stride; int bpp; int yb, xb; InterBlock *blocks; - int nb_blocks; + unsigned nb_blocks; } FMVCContext; static int decode_type2(GetByteContext *gb, PutByteContext *pb) @@ -150,7 +150,7 @@ static int decode_type2(GetByteContext *gb, PutByteContext *pb) if (opcode >= 0x40) { bytestream2_skip(gb, 1); pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb); - len = (opcode >> 5) - 1; + len = (opcode >> 5) - 1; bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); @@ -305,7 +305,7 @@ static int decode_type1(GetByteContext *gb, PutByteContext *pb) break; opcode = bytestream2_get_byte(gb); if (opcode < 0xF8) { - opcode = opcode + 32; + opcode += 32; break; } i = opcode - 0xF8; @@ -393,9 +393,8 @@ static int decode_type1(GetByteContext *gb, PutByteContext *pb) return 0; } -static int decode_frame(AVCodecContext *avctx, - void *data, int *got_frame, - AVPacket *avpkt) +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) { FMVCContext *s = avctx->priv_data; GetByteContext *gb = &s->gb; @@ -414,7 +413,7 @@ static int decode_frame(AVCodecContext *avctx, if (frame->key_frame) { const uint8_t *src; - int type, size; + unsigned type, size; uint8_t *dst; type = bytestream2_get_le16(gb); @@ -428,7 +427,7 @@ static int decode_frame(AVCodecContext *avctx, } else if (type == 2){ decode_type2(gb, pb); } else { - avpriv_report_missing_feature(avctx, "compression %d", type); + avpriv_report_missing_feature(avctx, "Compression type %d", type); return AVERROR_PATCHWELCOME; } @@ -440,7 +439,8 @@ static int decode_frame(AVCodecContext *avctx, src += s->stride * 4; } } else { - int block, nb_blocks, type, k, l; + unsigned block, nb_blocks; + int type, k, l; uint8_t *ssrc, *ddst; const uint32_t *src; uint32_t *dst; @@ -456,7 +456,8 @@ static int decode_frame(AVCodecContext *avctx, type = bytestream2_get_le16(gb); for (block = 0; block < nb_blocks; block++) { - int size, offset, start = 0; + unsigned size, offset; + int start = 0; offset = bytestream2_get_le16(gb); if (offset >= s->nb_blocks) @@ -472,7 +473,7 @@ static int decode_frame(AVCodecContext *avctx, } else if (type == 2){ decode_type2(gb, pb); } else { - avpriv_report_missing_feature(avctx, "compression %d", type); + avpriv_report_missing_feature(avctx, "Compression type %d", type); return AVERROR_PATCHWELCOME; } @@ -497,9 +498,8 @@ static int decode_frame(AVCodecContext *avctx, if (s->blocks[block].xor) { for (k = 0; k < block_h; k++) { uint32_t *column = dst; - for (l = 0; l < block_w; l++) { + for (l = 0; l < block_w; l++) *dst++ ^= *src++; - } dst = &column[s->stride]; } } @@ -529,17 +529,24 @@ static av_cold int decode_init(AVCodecContext *avctx) int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH; switch (avctx->bits_per_coded_sample) { - case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break; - case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; - case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break; + case 16: + avctx->pix_fmt = AV_PIX_FMT_RGB555; + break; + case 24: + avctx->pix_fmt = AV_PIX_FMT_BGR24; + break; + case 32: + avctx->pix_fmt = AV_PIX_FMT_BGRA; + break; default: - av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", avctx->bits_per_coded_sample); + av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", + avctx->bits_per_coded_sample); return AVERROR_INVALIDDATA; } s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32; - s->xb = s->stride / BLOCK_WIDTH; - m = s->stride % BLOCK_WIDTH; + s->xb = s->stride / BLOCK_WIDTH; + m = s->stride % BLOCK_WIDTH; if (m) { if (m < 37) { w = m + BLOCK_WIDTH; @@ -550,7 +557,7 @@ static av_cold int decode_init(AVCodecContext *avctx) } s->yb = avctx->height / BLOCK_HEIGHT; - m = avctx->height % BLOCK_HEIGHT; + m = avctx->height % BLOCK_HEIGHT; if (m) { if (m < 49) { h = m + BLOCK_HEIGHT; @@ -563,8 +570,7 @@ static av_cold int decode_init(AVCodecContext *avctx) s->nb_blocks = s->xb * s->yb; if (!s->nb_blocks) return AVERROR_INVALIDDATA; - - s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks)); + s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks)); if (!s->blocks) return AVERROR(ENOMEM); @@ -572,32 +578,32 @@ static av_cold int decode_init(AVCodecContext *avctx) for (j = 0; j < s->xb; j++) { if (i != (s->yb - 1) || j != (s->xb - 1)) { if (i == s->yb - 1) { - s->blocks[block].w = BLOCK_WIDTH; - s->blocks[block].h = h; + s->blocks[block].w = BLOCK_WIDTH; + s->blocks[block].h = h; s->blocks[block].size = BLOCK_WIDTH * h; } else if (j == s->xb - 1) { - s->blocks[block].w = w; - s->blocks[block].h = BLOCK_HEIGHT; + s->blocks[block].w = w; + s->blocks[block].h = BLOCK_HEIGHT; s->blocks[block].size = BLOCK_HEIGHT * w; } else { - s->blocks[block].w = BLOCK_WIDTH; - s->blocks[block].h = BLOCK_HEIGHT; + s->blocks[block].w = BLOCK_WIDTH; + s->blocks[block].h = BLOCK_HEIGHT; s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT; } } else { - s->blocks[block].w = w; - s->blocks[block].h = h; + s->blocks[block].w = w; + s->blocks[block].h = h; s->blocks[block].size = w * h; } block++; } } - s->bpp = avctx->bits_per_coded_sample >> 3; - s->buffer_size = avctx->width * avctx->height * 4; + s->bpp = avctx->bits_per_coded_sample >> 3; + s->buffer_size = avctx->width * avctx->height * 4; s->pbuffer_size = avctx->width * avctx->height * 4; - s->buffer = av_mallocz(s->buffer_size); - s->pbuffer = av_mallocz(s->pbuffer_size); + s->buffer = av_mallocz(s->buffer_size); + s->pbuffer = av_mallocz(s->pbuffer_size); if (!s->buffer || !s->pbuffer) return AVERROR(ENOMEM); diff --git a/libavcodec/gdv.c b/libavcodec/gdv.c index dc91869ed..e52a63761 100644 --- a/libavcodec/gdv.c +++ b/libavcodec/gdv.c @@ -409,17 +409,20 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, unsigned flags; uint8_t *dst; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - if (pal && pal_size == AVPALETTE_SIZE) - memcpy(gdv->pal, pal, AVPALETTE_SIZE); - bytestream2_init(gb, avpkt->data, avpkt->size); bytestream2_init_writer(pb, gdv->frame, gdv->frame_size); flags = bytestream2_get_le32(gb); compression = flags & 0xF; + if (compression == 4 || compression == 7 || compression > 8) + return AVERROR_INVALIDDATA; + + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + if (pal && pal_size == AVPALETTE_SIZE) + memcpy(gdv->pal, pal, AVPALETTE_SIZE); + rescale(gdv, gdv->frame, avctx->width, avctx->height, !!(flags & 0x10), !!(flags & 0x20)); @@ -451,7 +454,7 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, ret = decompress_68(avctx, flags >> 8, 1); break; default: - return AVERROR_INVALIDDATA; + av_assert0(0); } memcpy(frame->data[1], gdv->pal, AVPALETTE_SIZE); diff --git a/libavcodec/h263.h b/libavcodec/h263.h index d154d3663..f891f7237 100644 --- a/libavcodec/h263.h +++ b/libavcodec/h263.h @@ -27,9 +27,7 @@ #include "h263data.h" #include "rl.h" -#if !FF_API_ASPECT_EXTENDED #define FF_ASPECT_EXTENDED 15 -#endif #define INT_BIT (CHAR_BIT * sizeof(int)) // The defines below define the number of bits that are read at once for diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index bcb2b08bb..5608b6324 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -33,6 +33,7 @@ #include "flv.h" #include "h263.h" #include "h263_parser.h" +#include "hwaccel.h" #include "internal.h" #include "mpeg_er.h" #include "mpeg4video.h" @@ -41,7 +42,6 @@ #include "mpegvideo.h" #include "msmpeg4.h" #include "qpeldsp.h" -#include "vdpau_compat.h" #include "thread.h" #include "wmv2.h" @@ -603,13 +603,6 @@ retry: if (!s->divx_packed) ff_thread_finish_setup(avctx); -#if FF_API_CAP_VDPAU - if (CONFIG_MPEG4_VDPAU_DECODER && (s->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU)) { - ff_vdpau_mpeg4_decode_picture(avctx->priv_data, s->gb.buffer, s->gb.buffer_end - s->gb.buffer); - goto frame_end; - } -#endif - if (avctx->hwaccel) { ret = avctx->hwaccel->start_frame(avctx, s->gb.buffer, s->gb.buffer_end - s->gb.buffer); @@ -722,6 +715,9 @@ const enum AVPixelFormat ff_h263_hwaccel_pixfmt_list_420[] = { #if CONFIG_H263_VAAPI_HWACCEL || CONFIG_MPEG4_VAAPI_HWACCEL AV_PIX_FMT_VAAPI, #endif +#if CONFIG_MPEG4_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_MPEG4_VDPAU_HWACCEL AV_PIX_FMT_VDPAU, #endif @@ -764,4 +760,16 @@ AVCodec ff_h263p_decoder = { .flush = ff_mpeg_flush, .max_lowres = 3, .pix_fmts = ff_h263_hwaccel_pixfmt_list_420, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_H263_VAAPI_HWACCEL + HWACCEL_VAAPI(h263), +#endif +#if CONFIG_MPEG4_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg4), +#endif +#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(h263), +#endif + NULL + }, }; diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 86df5eb9b..650580bf3 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -44,4 +44,49 @@ enum { H264_NAL_AUXILIARY_SLICE = 19, }; + +enum { + // 7.4.2.1.1: seq_parameter_set_id is in [0, 31]. + H264_MAX_SPS_COUNT = 32, + // 7.4.2.2: pic_parameter_set_id is in [0, 255]. + H264_MAX_PPS_COUNT = 256, + + // A.3: MaxDpbFrames is bounded above by 16. + H264_MAX_DPB_FRAMES = 16, + // 7.4.2.1.1: max_num_ref_frames is in [0, MaxDpbFrames], and + // each reference frame can have two fields. + H264_MAX_REFS = 2 * H264_MAX_DPB_FRAMES, + + // 7.4.3.1: modification_of_pic_nums_idc is not equal to 3 at most + // num_ref_idx_lN_active_minus1 + 1 times (that is, once for each + // possible reference), then equal to 3 once. + H264_MAX_RPLM_COUNT = H264_MAX_REFS + 1, + + // 7.4.3.3: in the worst case, we begin with a full short-term + // reference picture list. Each picture in turn is moved to the + // long-term list (type 3) and then discarded from there (type 2). + // Then, we set the length of the long-term list (type 4), mark + // the current picture as long-term (type 6) and terminate the + // process (type 0). + H264_MAX_MMCO_COUNT = H264_MAX_REFS * 2 + 3, + + // A.2.1, A.2.3: profiles supporting FMO constrain + // num_slice_groups_minus1 to be in [0, 7]. + H264_MAX_SLICE_GROUPS = 8, + + // E.2.2: cpb_cnt_minus1 is in [0, 31]. + H264_MAX_CPB_CNT = 32, + + // A.3: in table A-1 the highest level allows a MaxFS of 139264. + H264_MAX_MB_PIC_SIZE = 139264, + // A.3.1, A.3.2: PicWidthInMbs and PicHeightInMbs are constrained + // to be not greater than sqrt(MaxFS * 8). Hence height/width are + // bounded above by sqrt(139264 * 8) = 1055.5 macroblocks. + H264_MAX_MB_WIDTH = 1055, + H264_MAX_MB_HEIGHT = 1055, + H264_MAX_WIDTH = H264_MAX_MB_WIDTH * 16, + H264_MAX_HEIGHT = H264_MAX_MB_HEIGHT * 16, +}; + + #endif /* AVCODEC_H264_H */ diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c index b0d9ff66f..e6c40381b 100644 --- a/libavcodec/h2645_parse.c +++ b/libavcodec/h2645_parse.c @@ -26,15 +26,15 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" +#include "bytestream.h" #include "hevc.h" #include "h2645_parse.h" int ff_h2645_extract_rbsp(const uint8_t *src, int length, - H2645NAL *nal, int small_padding) + H2645RBSP *rbsp, H2645NAL *nal, int small_padding) { int i, si, di; uint8_t *dst; - int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; nal->skipped_bytes = 0; #define STARTCODE_TEST \ @@ -91,11 +91,7 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, } else if (i > length) i = length; - av_fast_padded_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size, - length + padding); - if (!nal->rbsp_buffer) - return AVERROR(ENOMEM); - + nal->rbsp_buffer = &rbsp->rbsp_buffer[rbsp->rbsp_buffer_size]; dst = nal->rbsp_buffer; memcpy(dst, src, i); @@ -144,6 +140,8 @@ nsc: nal->size = di; nal->raw_data = src; nal->raw_size = si; + rbsp->rbsp_buffer_size += si; + return si; } @@ -247,60 +245,79 @@ static int h264_parse_nal_header(H2645NAL *nal, void *logctx) return 1; } +static int find_next_start_code(const uint8_t *buf, const uint8_t *next_avc) +{ + int i = 0; + + if (buf + 3 >= next_avc) + return next_avc - buf; + + while (buf + i + 3 < next_avc) { + if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) + break; + i++; + } + return i + 3; +} + int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, void *logctx, int is_nalff, int nal_length_size, enum AVCodecID codec_id, int small_padding) { + GetByteContext bc; int consumed, ret = 0; - const uint8_t *next_avc = is_nalff ? buf : buf + length; + int next_avc = is_nalff ? 0 : length; + int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; + bytestream2_init(&bc, buf, length); + av_fast_padded_malloc(&pkt->rbsp.rbsp_buffer, &pkt->rbsp.rbsp_buffer_alloc_size, length + padding); + if (!pkt->rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + + pkt->rbsp.rbsp_buffer_size = 0; pkt->nb_nals = 0; - while (length >= 4) { + while (bytestream2_get_bytes_left(&bc) >= 4) { H2645NAL *nal; int extract_length = 0; int skip_trailing_zeros = 1; - if (buf == next_avc) { + if (bytestream2_tell(&bc) == next_avc) { int i = 0; extract_length = get_nalsize(nal_length_size, - buf, length, &i, logctx); + bc.buffer, bytestream2_get_bytes_left(&bc), &i, logctx); if (extract_length < 0) return extract_length; - buf += nal_length_size; - length -= nal_length_size; + bytestream2_skip(&bc, nal_length_size); - next_avc = buf + extract_length; + next_avc = bytestream2_tell(&bc) + extract_length; } else { - if (buf > next_avc) + int buf_index; + + if (bytestream2_tell(&bc) > next_avc) av_log(logctx, AV_LOG_WARNING, "Exceeded next NALFF position, re-syncing.\n"); /* search start code */ - while (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) { - ++buf; - --length; - if (length < 4) { - if (pkt->nb_nals > 0) { - // No more start codes: we discarded some irrelevant - // bytes at the end of the packet. - return 0; - } else { - av_log(logctx, AV_LOG_ERROR, "No start code is found.\n"); - return AVERROR_INVALIDDATA; - } - } else if (buf >= (next_avc - 3)) - break; + buf_index = find_next_start_code(bc.buffer, buf + next_avc); + + bytestream2_skip(&bc, buf_index); + + if (!bytestream2_get_bytes_left(&bc)) { + if (pkt->nb_nals > 0) { + // No more start codes: we discarded some irrelevant + // bytes at the end of the packet. + return 0; + } else { + av_log(logctx, AV_LOG_ERROR, "No start code is found.\n"); + return AVERROR_INVALIDDATA; + } } - buf += 3; - length -= 3; - extract_length = FFMIN(length, next_avc - buf); + extract_length = FFMIN(bytestream2_get_bytes_left(&bc), next_avc - bytestream2_tell(&bc)); - if (buf >= next_avc) { + if (bytestream2_tell(&bc) >= next_avc) { /* skip to the start of the next NAL */ - int offset = next_avc - buf; - buf += offset; - length -= offset; + bytestream2_skip(&bc, next_avc - bytestream2_tell(&bc)); continue; } } @@ -326,7 +343,7 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, } nal = &pkt->nals[pkt->nb_nals]; - consumed = ff_h2645_extract_rbsp(buf, extract_length, nal, small_padding); + consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal, small_padding); if (consumed < 0) return consumed; @@ -337,10 +354,11 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, pkt->nb_nals++; + bytestream2_skip(&bc, consumed); + /* see commit 3566042a0 */ - if (consumed < length - 3 && - buf[consumed] == 0x00 && buf[consumed + 1] == 0x00 && - buf[consumed + 2] == 0x01 && buf[consumed + 3] == 0xE0) + if (bytestream2_get_bytes_left(&bc) >= 4 && + bytestream2_peek_be32(&bc) == 0x000001E0) skip_trailing_zeros = 0; nal->size_bits = get_bit_length(nal, skip_trailing_zeros); @@ -360,9 +378,6 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, } pkt->nb_nals--; } - - buf += consumed; - length -= consumed; } return 0; @@ -372,9 +387,10 @@ void ff_h2645_packet_uninit(H2645Packet *pkt) { int i; for (i = 0; i < pkt->nals_allocated; i++) { - av_freep(&pkt->nals[i].rbsp_buffer); av_freep(&pkt->nals[i].skipped_bytes_pos); } av_freep(&pkt->nals); pkt->nals_allocated = 0; + av_freep(&pkt->rbsp.rbsp_buffer); + pkt->rbsp.rbsp_buffer_alloc_size = pkt->rbsp.rbsp_buffer_size = 0; } diff --git a/libavcodec/h2645_parse.h b/libavcodec/h2645_parse.h index 5f3e17a0f..2e29ad26c 100644 --- a/libavcodec/h2645_parse.h +++ b/libavcodec/h2645_parse.h @@ -30,7 +30,6 @@ typedef struct H2645NAL { uint8_t *rbsp_buffer; - int rbsp_buffer_size; int size; const uint8_t *data; @@ -65,9 +64,16 @@ typedef struct H2645NAL { int ref_idc; } H2645NAL; +typedef struct H2645RBSP { + uint8_t *rbsp_buffer; + int rbsp_buffer_alloc_size; + int rbsp_buffer_size; +} H2645RBSP; + /* an input packet split into unescaped NAL units */ typedef struct H2645Packet { H2645NAL *nals; + H2645RBSP rbsp; int nb_nals; int nals_allocated; } H2645Packet; @@ -75,7 +81,7 @@ typedef struct H2645Packet { /** * Extract the raw (unescaped) bitstream. */ -int ff_h2645_extract_rbsp(const uint8_t *src, int length, +int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, H2645NAL *nal, int small_padding); /** diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 345834645..ec5fc74b9 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -2347,7 +2347,7 @@ decode_intra_mb: if (CHROMA444(h) && IS_8x8DCT(mb_type)){ int i; uint8_t *nnz_cache = sl->non_zero_count_cache; - if (h->sei.unregistered.x264_build < 151U) { + if (h->x264_build < 151U) { for (i = 0; i < 2; i++){ if (sl->left_type[LEFT(i)] && !IS_8x8DCT(sl->left_type[LEFT(i)])) { nnz_cache[3+8* 1 + 2*8*i]= diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c index a7a107c8c..ec9fca035 100644 --- a/libavcodec/h264_direct.c +++ b/libavcodec/h264_direct.c @@ -410,7 +410,7 @@ single_col: (l1ref0[0] < 0 && !l1ref1[0] && FFABS(l1mv1[0][0]) <= 1 && FFABS(l1mv1[0][1]) <= 1 && - h->sei.unregistered.x264_build > 33U))) { + h->x264_build > 33U))) { a = b = 0; if (ref[0] > 0) a = mv[0]; @@ -445,7 +445,7 @@ single_col: (l1ref0[i8] == 0 || (l1ref0[i8] < 0 && l1ref1[i8] == 0 && - h->sei.unregistered.x264_build > 33U))) { + h->x264_build > 33U))) { const int16_t (*l1mv)[2] = l1ref0[i8] == 0 ? l1mv0 : l1mv1; if (IS_SUB_8X8(sub_mb_type)) { const int16_t *mv_col = l1mv[x8 * 3 + y8 * 3 * b4_stride]; diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c index cb9fe856b..3cd17b7e4 100644 --- a/libavcodec/h264_mb.c +++ b/libavcodec/h264_mb.c @@ -637,7 +637,7 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h, uint8_t *const ptr = dest_y + block_offset[i]; const int dir = sl->intra4x4_pred_mode_cache[scan8[i]]; if (transform_bypass && h->ps.sps->profile_idc == 244 && dir <= 1) { - if (h->sei.unregistered.x264_build < 151U) { + if (h->x264_build < 151U) { h->hpc.pred8x8l_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift), linesize); } else h->hpc.pred8x8l_filter_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift), diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c new file mode 100644 index 000000000..ada40a57c --- /dev/null +++ b/libavcodec/h264_metadata_bsf.c @@ -0,0 +1,524 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/avstring.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_h264.h" +#include "h264.h" +#include "h264_sei.h" + +enum { + PASS, + INSERT, + REMOVE, +}; + +typedef struct H264MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment access_unit; + + H264RawAUD aud_nal; + H264RawSEI sei_nal; + + int aud; + + AVRational sample_aspect_ratio; + + int video_format; + int video_full_range_flag; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int chroma_sample_loc_type; + + AVRational tick_rate; + int fixed_frame_rate_flag; + + int crop_left; + int crop_right; + int crop_top; + int crop_bottom; + + const char *sei_user_data; + int sei_first_au; +} H264MetadataContext; + + +static int h264_metadata_update_sps(AVBSFContext *bsf, + H264RawSPS *sps) +{ + H264MetadataContext *ctx = bsf->priv_data; + int need_vui = 0; + int crop_unit_x, crop_unit_y; + + if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) { + // Table E-1. + static const AVRational sar_idc[] = { + { 0, 0 }, // Unspecified (never written here). + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int num, den, i; + + av_reduce(&num, &den, ctx->sample_aspect_ratio.num, + ctx->sample_aspect_ratio.den, 65535); + + for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) + break; + } + if (i == FF_ARRAY_ELEMS(sar_idc)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = num; + sps->vui.sar_height = den; + } else { + sps->vui.aspect_ratio_idc = i; + } + sps->vui.aspect_ratio_info_present_flag = 1; + need_vui = 1; + } + +#define SET_OR_INFER(field, value, present_flag, infer) do { \ + if (value >= 0) { \ + field = value; \ + need_vui = 1; \ + } else if (!present_flag) \ + field = infer; \ + } while (0) + + if (ctx->video_format >= 0 || + ctx->video_full_range_flag >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.video_format, ctx->video_format, + sps->vui.video_signal_type_present_flag, 5); + + SET_OR_INFER(sps->vui.video_full_range_flag, + ctx->video_full_range_flag, + sps->vui.video_signal_type_present_flag, 0); + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.colour_primaries, + ctx->colour_primaries, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.transfer_characteristics, + ctx->transfer_characteristics, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.matrix_coefficients, + ctx->matrix_coefficients, + sps->vui.colour_description_present_flag, 2); + + sps->vui.colour_description_present_flag = 1; + } + sps->vui.video_signal_type_present_flag = 1; + need_vui = 1; + } + + if (ctx->chroma_sample_loc_type >= 0) { + sps->vui.chroma_sample_loc_type_top_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_sample_loc_type_bottom_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_loc_info_present_flag = 1; + need_vui = 1; + } + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + sps->vui.time_scale = num; + sps->vui.num_units_in_tick = den; + + sps->vui.timing_info_present_flag = 1; + need_vui = 1; + } + SET_OR_INFER(sps->vui.fixed_frame_rate_flag, + ctx->fixed_frame_rate_flag, + sps->vui.timing_info_present_flag, 0); + + if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) { + crop_unit_x = 1; + crop_unit_y = 2 - sps->frame_mbs_only_flag; + } else { + crop_unit_x = 1 + (sps->chroma_format_idc < 3); + crop_unit_y = (1 + (sps->chroma_format_idc < 2)) * + (2 - sps->frame_mbs_only_flag); + } +#define CROP(border, unit) do { \ + if (ctx->crop_ ## border >= 0) { \ + if (ctx->crop_ ## border % unit != 0) { \ + av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \ + "must be a multiple of %d.\n", #border, unit); \ + return AVERROR(EINVAL); \ + } \ + sps->frame_crop_ ## border ## _offset = \ + ctx->crop_ ## border / unit; \ + sps->frame_cropping_flag = 1; \ + } \ + } while (0) + CROP(left, crop_unit_x); + CROP(right, crop_unit_x); + CROP(top, crop_unit_y); + CROP(bottom, crop_unit_y); +#undef CROP + + if (need_vui) + sps->vui_parameters_present_flag = 1; + + return 0; +} + +static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + H264MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i, j, has_sps; + char *sei_udu_string = NULL; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + goto fail; + + err = ff_cbs_read_packet(ctx->cbc, au, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + if (au->nb_units == 0) { + av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + // If an AUD is present, it must be the first NAL unit. + if (au->units[0].type == H264_NAL_AUD) { + if (ctx->aud == REMOVE) + ff_cbs_delete_unit(ctx->cbc, au, 0); + } else { + if (ctx->aud == INSERT) { + static const int primary_pic_type_table[] = { + 0x084, // 2, 7 + 0x0a5, // 0, 2, 5, 7 + 0x0e7, // 0, 1, 2, 5, 6, 7 + 0x210, // 4, 9 + 0x318, // 3, 4, 8, 9 + 0x294, // 2, 4, 7, 9 + 0x3bd, // 0, 2, 3, 4, 5, 7, 8, 9 + 0x3ff, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + int primary_pic_type_mask = 0xff; + H264RawAUD *aud = &ctx->aud_nal; + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SLICE || + au->units[i].type == H264_NAL_IDR_SLICE) { + H264RawSlice *slice = au->units[i].content; + for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) { + if (!(primary_pic_type_table[j] & + (1 << slice->header.slice_type))) + primary_pic_type_mask &= ~(1 << j); + } + } + } + for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) + if (primary_pic_type_mask & (1 << j)) + break; + if (j >= FF_ARRAY_ELEMS(primary_pic_type_table)) { + av_log(bsf, AV_LOG_ERROR, "No usable primary_pic_type: " + "invalid slice types?\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + aud->nal_unit_header.nal_unit_type = H264_NAL_AUD; + aud->primary_pic_type = j; + + err = ff_cbs_insert_unit_content(ctx->cbc, au, + 0, H264_NAL_AUD, aud); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); + goto fail; + } + } + } + + has_sps = 0; + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SPS) { + err = h264_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + has_sps = 1; + } + } + + // Insert the SEI in access units containing SPSs, and also + // unconditionally in the first access unit we ever see. + if (ctx->sei_user_data && (has_sps || !ctx->sei_first_au)) { + H264RawSEI *sei; + H264RawSEIPayload *payload; + H264RawSEIUserDataUnregistered *udu; + int sei_pos, sei_new; + + ctx->sei_first_au = 1; + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SEI || + au->units[i].type == H264_NAL_SLICE || + au->units[i].type == H264_NAL_IDR_SLICE) + break; + } + sei_pos = i; + + if (sei_pos < au->nb_units && + au->units[sei_pos].type == H264_NAL_SEI) { + sei_new = 0; + sei = au->units[sei_pos].content; + } else { + sei_new = 1; + sei = &ctx->sei_nal; + memset(sei, 0, sizeof(*sei)); + + sei->nal_unit_header.nal_unit_type = H264_NAL_SEI; + + err = ff_cbs_insert_unit_content(ctx->cbc, au, + sei_pos, H264_NAL_SEI, sei); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert SEI.\n"); + goto fail; + } + } + + payload = &sei->payload[sei->payload_count]; + + payload->payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED; + udu = &payload->payload.user_data_unregistered; + + for (i = j = 0; j < 32 && ctx->sei_user_data[i]; i++) { + int c, v; + c = ctx->sei_user_data[i]; + if (c == '-') { + continue; + } else if (av_isxdigit(c)) { + c = av_tolower(c); + v = (c <= '9' ? c - '0' : c - 'a' + 10); + } else { + goto invalid_user_data; + } + if (i & 1) + udu->uuid_iso_iec_11578[j / 2] |= v; + else + udu->uuid_iso_iec_11578[j / 2] = v << 4; + ++j; + } + if (j == 32 && ctx->sei_user_data[i] == '+') { + sei_udu_string = av_strdup(ctx->sei_user_data + i + 1); + if (!sei_udu_string) { + err = AVERROR(ENOMEM); + goto sei_fail; + } + + udu->data = sei_udu_string; + udu->data_length = strlen(sei_udu_string); + + payload->payload_size = 16 + udu->data_length; + + if (!sei_new) { + // This will be freed by the existing internal + // reference in fragment_uninit(). + sei_udu_string = NULL; + } + + } else { + invalid_user_data: + av_log(bsf, AV_LOG_ERROR, "Invalid user data: " + "must be \"UUID+string\".\n"); + err = AVERROR(EINVAL); + sei_fail: + memset(payload, 0, sizeof(*payload)); + goto fail; + } + + ++sei->payload_count; + } + + err = ff_cbs_write_packet(ctx->cbc, out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) + goto fail; + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + av_freep(&sei_udu_string); + + av_packet_free(&in); + + return err; +} + +static int h264_metadata_init(AVBSFContext *bsf) +{ + H264MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_H264, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, au, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SPS) { + err = h264_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + return err; +} + +static void h264_metadata_close(AVBSFContext *bsf) +{ + H264MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(H264MetadataContext, x) +static const AVOption h264_metadata_options[] = { + { "aud", "Access Unit Delimiter NAL units", + OFFSET(aud), AV_OPT_TYPE_INT, + { .i64 = PASS }, PASS, REMOVE, 0, "aud" }, + { "pass", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PASS }, .unit = "aud" }, + { "insert", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = INSERT }, .unit = "aud" }, + { "remove", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE }, .unit = "aud" }, + + { "sample_aspect_ratio", "Set sample aspect ratio (table E-1)", + OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, 65535 }, + + { "video_format", "Set video format (table E-2)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7 }, + { "video_full_range_flag", "Set video full range flag", + OFFSET(video_full_range_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1 }, + { "colour_primaries", "Set colour primaries (table E-3)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "transfer_characteristics", "Set transfer characteristics (table E-4)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "matrix_coefficients", "Set matrix coefficients (table E-5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + + { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)", + OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 6 }, + + { "tick_rate", "Set VUI tick rate (num_units_in_tick / time_scale)", + OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX }, + { "fixed_frame_rate_flag", "Set VUI fixed frame rate flag", + OFFSET(fixed_frame_rate_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1 }, + + { "crop_left", "Set left border crop offset", + OFFSET(crop_left), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_WIDTH }, + { "crop_right", "Set right border crop offset", + OFFSET(crop_right), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_WIDTH }, + { "crop_top", "Set top border crop offset", + OFFSET(crop_top), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_HEIGHT }, + { "crop_bottom", "Set bottom border crop offset", + OFFSET(crop_bottom), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_HEIGHT }, + + { "sei_user_data", "Insert SEI user data (UUID+string)", + OFFSET(sei_user_data), AV_OPT_TYPE_STRING, { .str = NULL } }, + + { NULL } +}; + +static const AVClass h264_metadata_class = { + .class_name = "h264_metadata_bsf", + .item_name = av_default_item_name, + .option = h264_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID h264_metadata_codec_ids[] = { + AV_CODEC_ID_H264, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_h264_metadata_bsf = { + .name = "h264_metadata", + .priv_data_size = sizeof(H264MetadataContext), + .priv_class = &h264_metadata_class, + .init = &h264_metadata_init, + .close = &h264_metadata_close, + .filter = &h264_metadata_filter, + .codec_ids = h264_metadata_codec_ids, +}; diff --git a/libavcodec/h264_parse.c b/libavcodec/h264_parse.c index a7c71d9bb..fee28d90d 100644 --- a/libavcodec/h264_parse.c +++ b/libavcodec/h264_parse.c @@ -425,10 +425,9 @@ static int decode_extradata_ps_mp4(const uint8_t *buf, int buf_size, H264ParamSe escaped_buf_size = bytestream2_tell_p(&pbc); AV_WB16(escaped_buf, escaped_buf_size - 2); - ret = decode_extradata_ps(escaped_buf, escaped_buf_size, ps, 1, logctx); + (void)decode_extradata_ps(escaped_buf, escaped_buf_size, ps, 1, logctx); + // lorex.mp4 decodes ok even with extradata decoding failing av_freep(&escaped_buf); - if (ret < 0) - return ret; } return 0; diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index dd0a965af..65d9d44b5 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -243,6 +243,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, const uint8_t * const buf, int buf_size) { H264ParseContext *p = s->priv_data; + H2645RBSP rbsp = { NULL }; H2645NAL nal = { NULL }; int buf_index, next_avc; unsigned int pps_id; @@ -258,11 +259,15 @@ static inline int parse_nal_units(AVCodecParserContext *s, s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; ff_h264_sei_uninit(&p->sei); - p->sei.frame_packing.frame_packing_arrangement_cancel_flag = -1; + p->sei.frame_packing.arrangement_cancel_flag = -1; if (!buf_size) return 0; + av_fast_padded_malloc(&rbsp.rbsp_buffer, &rbsp.rbsp_buffer_alloc_size, buf_size); + if (!rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + buf_index = 0; next_avc = p->is_avc ? 0 : buf_size; for (;;) { @@ -300,7 +305,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, } break; } - consumed = ff_h2645_extract_rbsp(buf + buf_index, src_length, &nal, 1); + consumed = ff_h2645_extract_rbsp(buf + buf_index, src_length, &rbsp, &nal, 1); if (consumed < 0) break; @@ -544,18 +549,18 @@ static inline int parse_nal_units(AVCodecParserContext *s, p->last_frame_num = p->poc.frame_num; } - av_freep(&nal.rbsp_buffer); + av_freep(&rbsp.rbsp_buffer); return 0; /* no need to evaluate the rest */ } } if (q264) { - av_freep(&nal.rbsp_buffer); + av_freep(&rbsp.rbsp_buffer); return 0; } /* didn't find a picture! */ av_log(avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size); fail: - av_freep(&nal.rbsp_buffer); + av_freep(&rbsp.rbsp_buffer); return -1; } diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c index 99d9f9075..e833835a7 100644 --- a/libavcodec/h264_picture.c +++ b/libavcodec/h264_picture.c @@ -41,7 +41,6 @@ #include "mpegutils.h" #include "rectangle.h" #include "thread.h" -#include "vdpau_compat.h" void ff_h264_unref_picture(H264Context *h, H264Picture *pic) { @@ -79,24 +78,30 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src) dst->qscale_table_buf = av_buffer_ref(src->qscale_table_buf); dst->mb_type_buf = av_buffer_ref(src->mb_type_buf); - if (!dst->qscale_table_buf || !dst->mb_type_buf) + if (!dst->qscale_table_buf || !dst->mb_type_buf) { + ret = AVERROR(ENOMEM); goto fail; + } dst->qscale_table = src->qscale_table; dst->mb_type = src->mb_type; for (i = 0; i < 2; i++) { dst->motion_val_buf[i] = av_buffer_ref(src->motion_val_buf[i]); dst->ref_index_buf[i] = av_buffer_ref(src->ref_index_buf[i]); - if (!dst->motion_val_buf[i] || !dst->ref_index_buf[i]) + if (!dst->motion_val_buf[i] || !dst->ref_index_buf[i]) { + ret = AVERROR(ENOMEM); goto fail; + } dst->motion_val[i] = src->motion_val[i]; dst->ref_index[i] = src->ref_index[i]; } if (src->hwaccel_picture_private) { dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); - if (!dst->hwaccel_priv_buf) + if (!dst->hwaccel_priv_buf) { + ret = AVERROR(ENOMEM); goto fail; + } dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; } @@ -152,12 +157,6 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup) int err = 0; h->mb_y = 0; -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - ff_vdpau_h264_set_reference_frames(h); -#endif - if (in_setup || !(avctx->active_thread_type & FF_THREAD_FRAME)) { if (!h->droppable) { err = ff_h264_execute_ref_pic_marking(h); @@ -175,12 +174,6 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup) "hardware accelerator failed to decode picture\n"); } -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - ff_vdpau_h264_picture_complete(h); -#endif - if (!in_setup && !h->droppable) ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, h->picture_structure == PICT_BOTTOM_FIELD); diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index b7d5f65d3..8d1ef831f 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -348,7 +348,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, sps->data_size = gb->buffer_end - gb->buffer; if (sps->data_size > sizeof(sps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized SPS\n"); + av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized SPS\n"); sps->data_size = sizeof(sps->data); } memcpy(sps->data, gb->buffer, sps->data_size); @@ -745,7 +745,7 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct pps->data_size = gb->buffer_end - gb->buffer; if (pps->data_size > sizeof(pps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized PPS " + av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized PPS " "(%"SIZE_SPECIFIER" > %"SIZE_SPECIFIER")\n", pps->data_size, sizeof(pps->data)); pps->data_size = sizeof(pps->data); diff --git a/libavcodec/h264_redundant_pps_bsf.c b/libavcodec/h264_redundant_pps_bsf.c new file mode 100644 index 000000000..26baca84e --- /dev/null +++ b/libavcodec/h264_redundant_pps_bsf.c @@ -0,0 +1,178 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/mem.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_h264.h" +#include "h264.h" + + +typedef struct H264RedundantPPSContext { + CodedBitstreamContext *input; + CodedBitstreamContext *output; + + CodedBitstreamFragment access_unit; + + int global_pic_init_qp; + int current_pic_init_qp; +} H264RedundantPPSContext; + + +static int h264_redundant_pps_fixup_pps(H264RedundantPPSContext *ctx, + H264RawPPS *pps) +{ + // Record the current value of pic_init_qp in order to fix up + // following slices, then overwrite with the global value. + ctx->current_pic_init_qp = pps->pic_init_qp_minus26 + 26; + pps->pic_init_qp_minus26 = ctx->global_pic_init_qp - 26; + + // Some PPSs have this set, so it must be set in all of them. + // (Slices which do not use such a PPS on input will still have + // *_weight_l*flag as zero and therefore write equivalently.) + pps->weighted_pred_flag = 1; + + return 0; +} + +static int h264_redundant_pps_fixup_slice(H264RedundantPPSContext *ctx, + H264RawSliceHeader *slice) +{ + int qp; + + qp = ctx->current_pic_init_qp + slice->slice_qp_delta; + slice->slice_qp_delta = qp - ctx->global_pic_init_qp; + + return 0; +} + +static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + AVPacket *in; + CodedBitstreamFragment *au = &ctx->access_unit; + int au_has_sps; + int err, i; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->input, au, in); + if (err < 0) + return err; + + au_has_sps = 0; + for (i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *nal = &au->units[i]; + + if (nal->type == H264_NAL_SPS) + au_has_sps = 1; + if (nal->type == H264_NAL_PPS) { + h264_redundant_pps_fixup_pps(ctx, nal->content); + if (!au_has_sps) { + av_log(ctx, AV_LOG_VERBOSE, "Deleting redundant PPS " + "at %"PRId64".\n", in->pts); + ff_cbs_delete_unit(ctx->input, au, i); + } + } + if (nal->type == H264_NAL_SLICE || + nal->type == H264_NAL_IDR_SLICE) { + H264RawSlice *slice = nal->content; + h264_redundant_pps_fixup_slice(ctx, &slice->header); + } + } + + err = ff_cbs_write_packet(ctx->output, out, au); + if (err < 0) + return err; + + ff_cbs_fragment_uninit(ctx->output, au); + + err = av_packet_copy_props(out, in); + if (err < 0) + return err; + + av_packet_free(&in); + + return 0; +} + +static int h264_redundant_pps_init(AVBSFContext *bsf) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_cbs_init(&ctx->input, AV_CODEC_ID_H264, bsf); + if (err < 0) + return err; + + err = ff_cbs_init(&ctx->output, AV_CODEC_ID_H264, bsf); + if (err < 0) + return err; + + ctx->global_pic_init_qp = 26; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->input, au, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + return err; + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_PPS) + h264_redundant_pps_fixup_pps(ctx, au->units[i].content); + } + + err = ff_cbs_write_extradata(ctx->output, bsf->par_out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + return err; + } + + ff_cbs_fragment_uninit(ctx->output, au); + } + + return 0; +} + +static void h264_redundant_pps_close(AVBSFContext *bsf) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->input); + ff_cbs_close(&ctx->output); +} + +static const enum AVCodecID h264_redundant_pps_codec_ids[] = { + AV_CODEC_ID_H264, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_h264_redundant_pps_bsf = { + .name = "h264_redundant_pps", + .priv_data_size = sizeof(H264RedundantPPSContext), + .init = &h264_redundant_pps_init, + .close = &h264_redundant_pps_close, + .filter = &h264_redundant_pps_filter, + .codec_ids = h264_redundant_pps_codec_ids, +}; diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index af7082959..976044ce2 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -614,6 +614,12 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) int current_ref_assigned = 0, err = 0; H264Picture *av_uninit(pic); + if (!h->ps.sps) { + av_log(h->avctx, AV_LOG_ERROR, "SPS is unset\n"); + err = AVERROR_INVALIDDATA; + goto out; + } + if (!h->explicit_ref_marking) generate_sliding_window_mmcos(h); mmco_count = h->nb_mmco; @@ -817,6 +823,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) h->frame_recovered |= FRAME_RECOVERED_SEI; } +out: return (h->avctx->err_recognition & AV_EF_EXPLODE) ? err : 0; } diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 332ae5086..9defcb80b 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -257,9 +257,6 @@ static int decode_unregistered_user_data(H264SEIUnregistered *h, GetBitContext * if (e == 1 && build == 1 && !strncmp(user_data+16, "x264 - core 0000", 16)) h->x264_build = 67; - if (strlen(user_data + 16) > 0) - av_log(logctx, AV_LOG_DEBUG, "user data:\"%s\"\n", user_data + 16); - av_free(user_data); return 0; } @@ -316,24 +313,25 @@ static int decode_buffering_period(H264SEIBufferingPeriod *h, GetBitContext *gb, static int decode_frame_packing_arrangement(H264SEIFramePacking *h, GetBitContext *gb) { - h->frame_packing_arrangement_id = get_ue_golomb_long(gb); - h->frame_packing_arrangement_cancel_flag = get_bits1(gb); - h->present = !h->frame_packing_arrangement_cancel_flag; + h->arrangement_id = get_ue_golomb_long(gb); + h->arrangement_cancel_flag = get_bits1(gb); + h->present = !h->arrangement_cancel_flag; if (h->present) { - h->frame_packing_arrangement_type = get_bits(gb, 7); + h->arrangement_type = get_bits(gb, 7); h->quincunx_sampling_flag = get_bits1(gb); h->content_interpretation_type = get_bits(gb, 6); - // the following skips: spatial_flipping_flag, frame0_flipped_flag, - // field_views_flag, current_frame_is_frame0_flag, + // spatial_flipping_flag, frame0_flipped_flag, field_views_flag + skip_bits(gb, 3); + h->current_frame_is_frame0_flag = get_bits1(gb); // frame0_self_contained_flag, frame1_self_contained_flag - skip_bits(gb, 6); + skip_bits(gb, 2); - if (!h->quincunx_sampling_flag && h->frame_packing_arrangement_type != 5) + if (!h->quincunx_sampling_flag && h->arrangement_type != 5) skip_bits(gb, 16); // frame[01]_grid_position_[xy] skip_bits(gb, 8); // frame_packing_arrangement_reserved_byte - h->frame_packing_arrangement_repetition_period = get_ue_golomb_long(gb); + h->arrangement_repetition_period = get_ue_golomb_long(gb); } skip_bits1(gb); // frame_packing_arrangement_extension_flag @@ -467,8 +465,8 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h) { - if (h->frame_packing_arrangement_cancel_flag == 0) { - switch (h->frame_packing_arrangement_type) { + if (h->arrangement_cancel_flag == 0) { + switch (h->arrangement_type) { case H264_SEI_FPA_TYPE_CHECKERBOARD: if (h->content_interpretation_type == 2) return "checkerboard_rl"; @@ -503,7 +501,7 @@ const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h) default: return "mono"; } - } else if (h->frame_packing_arrangement_cancel_flag == 1) { + } else if (h->arrangement_cancel_flag == 1) { return "mono"; } else { return NULL; diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index a53f1899f..9488382b9 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -119,12 +119,13 @@ typedef struct H264SEIBufferingPeriod { typedef struct H264SEIFramePacking { int present; - int frame_packing_arrangement_id; - int frame_packing_arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received - H264_SEI_FpaType frame_packing_arrangement_type; - int frame_packing_arrangement_repetition_period; + int arrangement_id; + int arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received + H264_SEI_FpaType arrangement_type; + int arrangement_repetition_period; int content_interpretation_type; int quincunx_sampling_flag; + int current_frame_is_frame0_flag; } H264SEIFramePacking; typedef struct H264SEIDisplayOrientation { diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 2577edd8a..e6b799883 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -399,12 +399,12 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->enable_er = h1->enable_er; h->workaround_bugs = h1->workaround_bugs; + h->x264_build = h1->x264_build; h->droppable = h1->droppable; // extradata/NAL handling h->is_avc = h1->is_avc; h->nal_length_size = h1->nal_length_size; - h->sei.unregistered.x264_build = h1->sei.unregistered.x264_build; memcpy(&h->poc, &h1->poc, sizeof(h->poc)); @@ -497,11 +497,7 @@ static int h264_frame_start(H264Context *h) if ((ret = alloc_picture(h, pic)) < 0) return ret; - if(!h->frame_recovered && !h->avctx->hwaccel -#if FF_API_CAP_VDPAU - && !(h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) -#endif - ) + if(!h->frame_recovered && !h->avctx->hwaccel) ff_color_frame(pic->f, c); h->cur_pic_ptr = pic; @@ -549,6 +545,9 @@ static int h264_frame_start(H264Context *h) h->mb_aff_frame = h->ps.sps->mb_aff && (h->picture_structure == PICT_FRAME); + if (h->sei.unregistered.x264_build >= 0) + h->x264_build = h->sei.unregistered.x264_build; + assert(h->cur_pic_ptr->long_ref == 0); return 0; @@ -758,8 +757,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) { #define HWACCEL_MAX (CONFIG_H264_DXVA2_HWACCEL + \ (CONFIG_H264_D3D11VA_HWACCEL * 2) + \ + CONFIG_H264_NVDEC_HWACCEL + \ CONFIG_H264_VAAPI_HWACCEL + \ - (CONFIG_H264_VDA_HWACCEL * 2) + \ CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \ CONFIG_H264_VDPAU_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; @@ -814,6 +813,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) case 8: #if CONFIG_H264_VDPAU_HWACCEL *fmt++ = AV_PIX_FMT_VDPAU; +#endif +#if CONFIG_H264_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif if (CHROMA444(h)) { if (h->avctx->colorspace == AVCOL_SPC_RGB) @@ -838,10 +840,6 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #if CONFIG_H264_VAAPI_HWACCEL *fmt++ = AV_PIX_FMT_VAAPI; #endif -#if CONFIG_H264_VDA_HWACCEL - *fmt++ = AV_PIX_FMT_VDA_VLD; - *fmt++ = AV_PIX_FMT_VDA; -#endif #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; #endif @@ -921,7 +919,7 @@ static int h264_slice_header_init(H264Context *h) if (sps->timing_info_present_flag) { int64_t den = sps->time_scale; - if (h->sei.unregistered.x264_build < 44U) + if (h->x264_build < 44U) den *= 2; av_reduce(&h->avctx->framerate.den, &h->avctx->framerate.num, sps->num_units_in_tick * h->avctx->ticks_per_frame, den, 1 << 30); @@ -939,17 +937,6 @@ static int h264_slice_header_init(H264Context *h) goto fail; } -#if FF_API_CAP_VDPAU - if (h->avctx->codec && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU && - (sps->bit_depth_luma != 8 || sps->chroma_format_idc > 1)) { - av_log(h->avctx, AV_LOG_ERROR, - "VDPAU decoding does not support video colorspace.\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } -#endif - if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 14 || sps->bit_depth_luma == 11 || sps->bit_depth_luma == 13 ) { @@ -1211,41 +1198,48 @@ static int h264_export_frame_props(H264Context *h) } if (h->sei.frame_packing.present && - h->sei.frame_packing.frame_packing_arrangement_type <= 6 && + h->sei.frame_packing.arrangement_type <= 6 && h->sei.frame_packing.content_interpretation_type > 0 && h->sei.frame_packing.content_interpretation_type < 3) { H264SEIFramePacking *fp = &h->sei.frame_packing; AVStereo3D *stereo = av_stereo3d_create_side_data(cur->f); if (stereo) { - switch (fp->frame_packing_arrangement_type) { - case 0: + switch (fp->arrangement_type) { + case H264_SEI_FPA_TYPE_CHECKERBOARD: stereo->type = AV_STEREO3D_CHECKERBOARD; break; - case 1: + case H264_SEI_FPA_TYPE_INTERLEAVE_COLUMN: stereo->type = AV_STEREO3D_COLUMNS; break; - case 2: + case H264_SEI_FPA_TYPE_INTERLEAVE_ROW: stereo->type = AV_STEREO3D_LINES; break; - case 3: + case H264_SEI_FPA_TYPE_SIDE_BY_SIDE: if (fp->quincunx_sampling_flag) stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; else stereo->type = AV_STEREO3D_SIDEBYSIDE; break; - case 4: + case H264_SEI_FPA_TYPE_TOP_BOTTOM: stereo->type = AV_STEREO3D_TOPBOTTOM; break; - case 5: + case H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL: stereo->type = AV_STEREO3D_FRAMESEQUENCE; break; - case 6: + case H264_SEI_FPA_TYPE_2D: stereo->type = AV_STEREO3D_2D; break; } if (fp->content_interpretation_type == 2) stereo->flags = AV_STEREO3D_FLAG_INVERT; + + if (fp->arrangement_type == H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL) { + if (fp->current_frame_is_frame0_flag) + stereo->view = AV_STEREO3D_VIEW_LEFT; + else + stereo->view = AV_STEREO3D_VIEW_RIGHT; + } } } @@ -1577,6 +1571,12 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, * one except for reference purposes. */ h->first_field = 1; h->cur_pic_ptr = NULL; + } else if (h->cur_pic_ptr->reference & DELAYED_PIC_REF) { + /* This frame was already output, we cannot draw into it + * anymore. + */ + h->first_field = 1; + h->cur_pic_ptr = NULL; } else { /* Second field in complementary pair */ h->first_field = 0; @@ -2738,11 +2738,7 @@ int ff_h264_execute_decode_slices(H264Context *h) h->slice_ctx[0].next_slice_idx = INT_MAX; - if (h->avctx->hwaccel || context_count < 1 -#if FF_API_CAP_VDPAU - || h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (h->avctx->hwaccel || context_count < 1) return 0; av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height); diff --git a/libavcodec/h264addpx_template.c b/libavcodec/h264addpx_template.c index b71aaea43..9a1e6a2f2 100644 --- a/libavcodec/h264addpx_template.c +++ b/libavcodec/h264addpx_template.c @@ -35,10 +35,10 @@ static void FUNCC(ff_h264_add_pixels4)(uint8_t *_dst, int16_t *_src, int stride) stride /= sizeof(pixel); for (i = 0; i < 4; i++) { - dst[0] += src[0]; - dst[1] += src[1]; - dst[2] += src[2]; - dst[3] += src[3]; + dst[0] += (unsigned)src[0]; + dst[1] += (unsigned)src[1]; + dst[2] += (unsigned)src[2]; + dst[3] += (unsigned)src[3]; dst += stride; src += 4; @@ -55,14 +55,14 @@ static void FUNCC(ff_h264_add_pixels8)(uint8_t *_dst, int16_t *_src, int stride) stride /= sizeof(pixel); for (i = 0; i < 8; i++) { - dst[0] += src[0]; - dst[1] += src[1]; - dst[2] += src[2]; - dst[3] += src[3]; - dst[4] += src[4]; - dst[5] += src[5]; - dst[6] += src[6]; - dst[7] += src[7]; + dst[0] += (unsigned)src[0]; + dst[1] += (unsigned)src[1]; + dst[2] += (unsigned)src[2]; + dst[3] += (unsigned)src[3]; + dst[4] += (unsigned)src[4]; + dst[5] += (unsigned)src[5]; + dst[6] += (unsigned)src[6]; + dst[7] += (unsigned)src[7]; dst += stride; src += 8; diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index f29c3f904..8c9c6d9f3 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -47,13 +47,13 @@ #include "h264_mvpred.h" #include "h264_ps.h" #include "golomb.h" +#include "hwaccel.h" #include "mathops.h" #include "me_cmp.h" #include "mpegutils.h" #include "profiles.h" #include "rectangle.h" #include "thread.h" -#include "vdpau_compat.h" const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 }; @@ -317,7 +317,7 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h) h->recovery_frame = -1; h->frame_recovered = 0; h->poc.prev_frame_num = -1; - h->sei.frame_packing.frame_packing_arrangement_cancel_flag = -1; + h->sei.frame_packing.arrangement_cancel_flag = -1; h->sei.unregistered.x264_build = -1; h->next_outputed_poc = INT_MIN; @@ -527,10 +527,6 @@ static void flush_dpb(AVCodecContext *avctx) h->context_initialized = 0; } -#if FF_API_CAP_VDPAU -static const uint8_t start_code[] = { 0x00, 0x00, 0x01 }; -#endif - static int get_last_needed_nal(H264Context *h) { int nals_needed = 0; @@ -688,11 +684,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) if (h->avctx->hwaccel && (ret = h->avctx->hwaccel->start_frame(h->avctx, buf, buf_size)) < 0) goto end; -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - ff_vdpau_h264_picture_start(h); -#endif } max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx; @@ -701,18 +692,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size); h->nb_slice_ctx_queued = 0; } else -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) { - ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0], - start_code, - sizeof(start_code)); - ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0], - nal->raw_data, - nal->raw_size); - ret = 0; - } else -#endif ret = ff_h264_execute_decode_slices(h); if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; @@ -728,16 +707,19 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) h->has_recovery_point = h->has_recovery_point || h->sei.recovery_point.recovery_frame_cnt != -1; if (avctx->debug & FF_DEBUG_GREEN_MD) debug_green_metadata(&h->sei.green_metadata, h->avctx); -#if FF_API_AFD -FF_DISABLE_DEPRECATION_WARNINGS - h->avctx->dtg_active_format = h->sei.afd.active_format_description; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_AFD */ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; break; case H264_NAL_SPS: { GetBitContext tmp_gb = nal->gb; + if (avctx->hwaccel && avctx->hwaccel->decode_params) { + ret = avctx->hwaccel->decode_params(avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto end; + } if (ff_h264_decode_seq_parameter_set(&tmp_gb, avctx, &h->ps, 0) >= 0) break; av_log(h->avctx, AV_LOG_DEBUG, @@ -749,6 +731,14 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } case H264_NAL_PPS: + if (avctx->hwaccel && avctx->hwaccel->decode_params) { + ret = avctx->hwaccel->decode_params(avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto end; + } ret = ff_h264_decode_picture_parameter_set(&nal->gb, avctx, &h->ps, nal->size_bits); if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) @@ -849,7 +839,7 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp) int ret; if (src->format == AV_PIX_FMT_VIDEOTOOLBOX && src->buf[0]->size == 1) - return AVERROR_EXTERNAL; + return AVERROR_INVALIDDATA; ret = av_frame_ref(dst, src); if (ret < 0) @@ -1046,6 +1036,7 @@ static const AVOption h264_options[] = { { "is_avc", "is avc", OFFSET(is_avc), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 0 }, { "nal_length_size", "nal_length_size", OFFSET(nal_length_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, 0 }, { "enable_er", "Enable error resilience on damaged frames (unsafe)", OFFSET(enable_er), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD }, + { "x264_build", "Assume this x264 version if no x264 version found in any SEI", OFFSET(x264_build), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VD }, { NULL }, }; @@ -1068,6 +1059,30 @@ AVCodec ff_h264_decoder = { .capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_H264_DXVA2_HWACCEL + HWACCEL_DXVA2(h264), +#endif +#if CONFIG_H264_D3D11VA_HWACCEL + HWACCEL_D3D11VA(h264), +#endif +#if CONFIG_H264_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(h264), +#endif +#if CONFIG_H264_NVDEC_HWACCEL + HWACCEL_NVDEC(h264), +#endif +#if CONFIG_H264_VAAPI_HWACCEL + HWACCEL_VAAPI(h264), +#endif +#if CONFIG_H264_VDPAU_HWACCEL + HWACCEL_VDPAU(h264), +#endif +#if CONFIG_H264_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(h264), +#endif + NULL + }, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .flush = flush_dpb, .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), @@ -1075,29 +1090,3 @@ AVCodec ff_h264_decoder = { .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), .priv_class = &h264_class, }; - -#if CONFIG_H264_VDPAU_DECODER && FF_API_VDPAU -static const AVClass h264_vdpau_class = { - .class_name = "H264 VDPAU Decoder", - .item_name = av_default_item_name, - .option = h264_options, - .version = LIBAVUTIL_VERSION_INT, -}; - -AVCodec ff_h264_vdpau_decoder = { - .name = "h264_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (VDPAU acceleration)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .priv_data_size = sizeof(H264Context), - .init = h264_decode_init, - .close = h264_decode_end, - .decode = h264_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HWACCEL_VDPAU, - .flush = flush_dpb, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VDPAU_H264, - AV_PIX_FMT_NONE}, - .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), - .priv_class = &h264_vdpau_class, -}; -#endif diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 2106ba077..1d9723260 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -365,6 +365,7 @@ typedef struct H264Context { int context_initialized; int flags; int workaround_bugs; + int x264_build; /* Set when slice threading is used and at least one slice uses deblocking * mode 1 (i.e. across slice boundaries). Then we disable the loop filter * during normal MB decoding and execute it serially at the end. @@ -416,6 +417,7 @@ typedef struct H264Context { uint8_t (*mvd_table[2])[2]; uint8_t *direct_table; + uint8_t scan_padding[16]; uint8_t zigzag_scan[16]; uint8_t zigzag_scan8x8[64]; uint8_t zigzag_scan8x8_cavlc[64]; diff --git a/libavcodec/h264idct_template.c b/libavcodec/h264idct_template.c index 3ad58c4a1..5993ae2e6 100644 --- a/libavcodec/h264idct_template.c +++ b/libavcodec/h264idct_template.c @@ -76,10 +76,10 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){ for( i = 0; i < 8; i++ ) { - const unsigned int a0 = block[i+0*8] + block[i+4*8]; - const unsigned int a2 = block[i+0*8] - block[i+4*8]; - const unsigned int a4 = (block[i+2*8]>>1) - block[i+6*8]; - const unsigned int a6 = (block[i+6*8]>>1) + block[i+2*8]; + const unsigned int a0 = block[i+0*8] + (unsigned)block[i+4*8]; + const unsigned int a2 = block[i+0*8] - (unsigned)block[i+4*8]; + const unsigned int a4 = (block[i+2*8]>>1) - (unsigned)block[i+6*8]; + const unsigned int a6 = (block[i+6*8]>>1) + (unsigned)block[i+2*8]; const unsigned int b0 = a0 + a6; const unsigned int b2 = a2 + a4; @@ -91,10 +91,10 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){ const int a5 = -block[i+1*8] + (unsigned)block[i+7*8] + block[i+5*8] + (block[i+5*8]>>1); const int a7 = block[i+3*8] + (unsigned)block[i+5*8] + block[i+1*8] + (block[i+1*8]>>1); - const int b1 = (a7>>2) + a1; - const int b3 = a3 + (a5>>2); - const int b5 = (a3>>2) - a5; - const int b7 = a7 - (a1>>2); + const int b1 = (a7>>2) + (unsigned)a1; + const int b3 = (unsigned)a3 + (a5>>2); + const int b5 = (a3>>2) - (unsigned)a5; + const int b7 = (unsigned)a7 - (a1>>2); block[i+0*8] = b0 + b7; block[i+7*8] = b0 - b7; @@ -107,10 +107,10 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){ } for( i = 0; i < 8; i++ ) { - const unsigned a0 = block[0+i*8] + block[4+i*8]; - const unsigned a2 = block[0+i*8] - block[4+i*8]; - const unsigned a4 = (block[2+i*8]>>1) - block[6+i*8]; - const unsigned a6 = (block[6+i*8]>>1) + block[2+i*8]; + const unsigned a0 = block[0+i*8] + (unsigned)block[4+i*8]; + const unsigned a2 = block[0+i*8] - (unsigned)block[4+i*8]; + const unsigned a4 = (block[2+i*8]>>1) - (unsigned)block[6+i*8]; + const unsigned a6 = (block[6+i*8]>>1) + (unsigned)block[2+i*8]; const unsigned b0 = a0 + a6; const unsigned b2 = a2 + a4; diff --git a/libavcodec/h265_metadata_bsf.c b/libavcodec/h265_metadata_bsf.c new file mode 100644 index 000000000..67dbe288e --- /dev/null +++ b/libavcodec/h265_metadata_bsf.c @@ -0,0 +1,458 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_h265.h" +#include "hevc.h" + +enum { + PASS, + INSERT, + REMOVE, +}; + +typedef struct H265MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment access_unit; + + H265RawAUD aud_nal; + + int aud; + + AVRational sample_aspect_ratio; + + int video_format; + int video_full_range_flag; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int chroma_sample_loc_type; + + AVRational tick_rate; + int poc_proportional_to_timing_flag; + int num_ticks_poc_diff_one; + + int crop_left; + int crop_right; + int crop_top; + int crop_bottom; +} H265MetadataContext; + + +static int h265_metadata_update_vps(AVBSFContext *bsf, + H265RawVPS *vps) +{ + H265MetadataContext *ctx = bsf->priv_data; + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + vps->vps_time_scale = num; + vps->vps_num_units_in_tick = den; + + vps->vps_timing_info_present_flag = 1; + + if (ctx->num_ticks_poc_diff_one > 0) { + vps->vps_num_ticks_poc_diff_one_minus1 = + ctx->num_ticks_poc_diff_one - 1; + vps->vps_poc_proportional_to_timing_flag = 1; + } else if (ctx->num_ticks_poc_diff_one == 0) { + vps->vps_poc_proportional_to_timing_flag = 0; + } + } + + return 0; +} + +static int h265_metadata_update_sps(AVBSFContext *bsf, + H265RawSPS *sps) +{ + H265MetadataContext *ctx = bsf->priv_data; + int need_vui = 0; + int crop_unit_x, crop_unit_y; + + if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) { + // Table E-1. + static const AVRational sar_idc[] = { + { 0, 0 }, // Unspecified (never written here). + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int num, den, i; + + av_reduce(&num, &den, ctx->sample_aspect_ratio.num, + ctx->sample_aspect_ratio.den, 65535); + + for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) + break; + } + if (i == FF_ARRAY_ELEMS(sar_idc)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = num; + sps->vui.sar_height = den; + } else { + sps->vui.aspect_ratio_idc = i; + } + sps->vui.aspect_ratio_info_present_flag = 1; + need_vui = 1; + } + +#define SET_OR_INFER(field, value, present_flag, infer) do { \ + if (value >= 0) { \ + field = value; \ + need_vui = 1; \ + } else if (!present_flag) \ + field = infer; \ + } while (0) + + if (ctx->video_format >= 0 || + ctx->video_full_range_flag >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.video_format, ctx->video_format, + sps->vui.video_signal_type_present_flag, 5); + + SET_OR_INFER(sps->vui.video_full_range_flag, + ctx->video_full_range_flag, + sps->vui.video_signal_type_present_flag, 0); + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.colour_primaries, + ctx->colour_primaries, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.transfer_characteristics, + ctx->transfer_characteristics, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.matrix_coefficients, + ctx->matrix_coefficients, + sps->vui.colour_description_present_flag, 2); + + sps->vui.colour_description_present_flag = 1; + } + sps->vui.video_signal_type_present_flag = 1; + need_vui = 1; + } + + if (ctx->chroma_sample_loc_type >= 0) { + sps->vui.chroma_sample_loc_type_top_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_sample_loc_type_bottom_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_loc_info_present_flag = 1; + need_vui = 1; + } + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + sps->vui.vui_time_scale = num; + sps->vui.vui_num_units_in_tick = den; + + sps->vui.vui_timing_info_present_flag = 1; + need_vui = 1; + + if (ctx->num_ticks_poc_diff_one > 0) { + sps->vui.vui_num_ticks_poc_diff_one_minus1 = + ctx->num_ticks_poc_diff_one - 1; + sps->vui.vui_poc_proportional_to_timing_flag = 1; + } else if (ctx->num_ticks_poc_diff_one == 0) { + sps->vui.vui_poc_proportional_to_timing_flag = 0; + } + } + + if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) { + crop_unit_x = 1; + crop_unit_y = 1; + } else { + crop_unit_x = 1 + (sps->chroma_format_idc < 3); + crop_unit_y = 1 + (sps->chroma_format_idc < 2); + } +#define CROP(border, unit) do { \ + if (ctx->crop_ ## border >= 0) { \ + if (ctx->crop_ ## border % unit != 0) { \ + av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \ + "must be a multiple of %d.\n", #border, unit); \ + return AVERROR(EINVAL); \ + } \ + sps->conf_win_ ## border ## _offset = \ + ctx->crop_ ## border / unit; \ + sps->conformance_window_flag = 1; \ + } \ + } while (0) + CROP(left, crop_unit_x); + CROP(right, crop_unit_x); + CROP(top, crop_unit_y); + CROP(bottom, crop_unit_y); +#undef CROP + + if (need_vui) + sps->vui_parameters_present_flag = 1; + + return 0; +} + +static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + H265MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + goto fail; + + err = ff_cbs_read_packet(ctx->cbc, au, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + if (au->nb_units == 0) { + av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + // If an AUD is present, it must be the first NAL unit. + if (au->units[0].type == HEVC_NAL_AUD) { + if (ctx->aud == REMOVE) + ff_cbs_delete_unit(ctx->cbc, au, 0); + } else { + if (ctx->aud == INSERT) { + H265RawAUD *aud = &ctx->aud_nal; + int pic_type = 0, temporal_id = 8, layer_id = 0; + + for (i = 0; i < au->nb_units; i++) { + const H265RawNALUnitHeader *nal = au->units[i].content; + if (!nal) + continue; + if (nal->nuh_temporal_id_plus1 < temporal_id + 1) + temporal_id = nal->nuh_temporal_id_plus1 - 1; + + if (au->units[i].type <= HEVC_NAL_RSV_VCL31) { + const H265RawSlice *slice = au->units[i].content; + layer_id = nal->nuh_layer_id; + if (slice->header.slice_type == HEVC_SLICE_B && + pic_type < 2) + pic_type = 2; + if (slice->header.slice_type == HEVC_SLICE_P && + pic_type < 1) + pic_type = 1; + } + } + + aud->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_AUD, + .nuh_layer_id = layer_id, + .nuh_temporal_id_plus1 = temporal_id + 1, + }; + aud->pic_type = pic_type; + + err = ff_cbs_insert_unit_content(ctx->cbc, au, + 0, HEVC_NAL_AUD, aud); + if (err) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); + goto fail; + } + } + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == HEVC_NAL_VPS) { + err = h265_metadata_update_vps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + if (au->units[i].type == HEVC_NAL_SPS) { + err = h265_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_packet(ctx->cbc, out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) + goto fail; + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + + av_packet_free(&in); + + return err; +} + +static int h265_metadata_init(AVBSFContext *bsf) +{ + H265MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_HEVC, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, au, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == HEVC_NAL_VPS) { + err = h265_metadata_update_vps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + if (au->units[i].type == HEVC_NAL_SPS) { + err = h265_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + return err; +} + +static void h265_metadata_close(AVBSFContext *bsf) +{ + H265MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(H265MetadataContext, x) +static const AVOption h265_metadata_options[] = { + { "aud", "Access Unit Delimiter NAL units", + OFFSET(aud), AV_OPT_TYPE_INT, + { .i64 = PASS }, PASS, REMOVE, 0, "aud" }, + { "pass", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PASS }, .unit = "aud" }, + { "insert", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = INSERT }, .unit = "aud" }, + { "remove", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE }, .unit = "aud" }, + + { "sample_aspect_ratio", "Set sample aspect ratio (table E-1)", + OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, 65535 }, + + { "video_format", "Set video format (table E-2)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7 }, + { "video_full_range_flag", "Set video full range flag", + OFFSET(video_full_range_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1 }, + { "colour_primaries", "Set colour primaries (table E-3)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "transfer_characteristics", "Set transfer characteristics (table E-4)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "matrix_coefficients", "Set matrix coefficients (table E-5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + + { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)", + OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 6 }, + + { "tick_rate", + "Set VPS and VUI tick rate (num_units_in_tick / time_scale)", + OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX }, + { "num_ticks_poc_diff_one", + "Set VPS and VUI number of ticks per POC increment", + OFFSET(num_ticks_poc_diff_one), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, INT_MAX }, + + { "crop_left", "Set left border crop offset", + OFFSET(crop_left), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_WIDTH }, + { "crop_right", "Set right border crop offset", + OFFSET(crop_right), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_WIDTH }, + { "crop_top", "Set top border crop offset", + OFFSET(crop_top), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_HEIGHT }, + { "crop_bottom", "Set bottom border crop offset", + OFFSET(crop_bottom), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_HEIGHT }, + + { NULL } +}; + +static const AVClass h265_metadata_class = { + .class_name = "h265_metadata_bsf", + .item_name = av_default_item_name, + .option = h265_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID h265_metadata_codec_ids[] = { + AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_hevc_metadata_bsf = { + .name = "hevc_metadata", + .priv_data_size = sizeof(H265MetadataContext), + .priv_class = &h265_metadata_class, + .init = &h265_metadata_init, + .close = &h265_metadata_close, + .filter = &h265_metadata_filter, + .codec_ids = h265_metadata_codec_ids, +}; diff --git a/libavcodec/hap.h b/libavcodec/hap.h index 0ee65335d..74455f3dd 100644 --- a/libavcodec/hap.h +++ b/libavcodec/hap.h @@ -73,6 +73,7 @@ typedef struct HapContext { int *chunk_results; /* Results from threaded operations */ int tex_rat; /* Compression ratio */ + int tex_rat2; /* Compression ratio of the second texture */ const uint8_t *tex_data; /* Compressed texture */ uint8_t *tex_buf; /* Buffer for compressed texture */ size_t tex_size; /* Size of the compressed texture */ @@ -81,8 +82,13 @@ typedef struct HapContext { int slice_count; /* Number of slices for threaded operations */ + int texture_count; /* 2 for HAQA, 1 for other version */ + int texture_section_size; /* size of the part of the texture section (for HAPQA) */ + int uncompress_pix_size; /* nb of byte / pixel for the target picture */ + /* Pointer to the selected compress or decompress function */ int (*tex_fun)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*tex_fun2)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); } HapContext; /* diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c index fc9dff10f..8fd4aa962 100644 --- a/libavcodec/hapdec.c +++ b/libavcodec/hapdec.c @@ -3,6 +3,8 @@ * Copyright (C) 2015 Vittorio Giovara * Copyright (C) 2015 Tom Butterworth * + * HapQA and HAPAlphaOnly added by Jokyo Images + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -157,14 +159,16 @@ static int hap_parse_frame_header(AVCodecContext *avctx) const char *compressorstr; int i, ret; - ret = parse_section_header(gbc, §ion_size, §ion_type); + ret = parse_section_header(gbc, &ctx->texture_section_size, §ion_type); if (ret != 0) return ret; if ((avctx->codec_tag == MKTAG('H','a','p','1') && (section_type & 0x0F) != HAP_FMT_RGBDXT1) || (avctx->codec_tag == MKTAG('H','a','p','5') && (section_type & 0x0F) != HAP_FMT_RGBADXT5) || (avctx->codec_tag == MKTAG('H','a','p','Y') && (section_type & 0x0F) != HAP_FMT_YCOCGDXT5) || - (avctx->codec_tag == MKTAG('H','a','p','A') && (section_type & 0x0F) != HAP_FMT_RGTC1)) { + (avctx->codec_tag == MKTAG('H','a','p','A') && (section_type & 0x0F) != HAP_FMT_RGTC1) || + ((avctx->codec_tag == MKTAG('H','a','p','M') && (section_type & 0x0F) != HAP_FMT_RGTC1) && + (section_type & 0x0F) != HAP_FMT_YCOCGDXT5)) { av_log(avctx, AV_LOG_ERROR, "Invalid texture format %#04x.\n", section_type & 0x0F); return AVERROR_INVALIDDATA; @@ -177,7 +181,7 @@ static int hap_parse_frame_header(AVCodecContext *avctx) if (ret == 0) { ctx->chunks[0].compressor = section_type & 0xF0; ctx->chunks[0].compressed_offset = 0; - ctx->chunks[0].compressed_size = section_size; + ctx->chunks[0].compressed_size = ctx->texture_section_size; } if (ctx->chunks[0].compressor == HAP_COMP_NONE) { compressorstr = "none"; @@ -266,8 +270,8 @@ static int decompress_chunks_thread(AVCodecContext *avctx, void *arg, return 0; } -static int decompress_texture_thread(AVCodecContext *avctx, void *arg, - int slice, int thread_nb) +static int decompress_texture_thread_internal(AVCodecContext *avctx, void *arg, + int slice, int thread_nb, int texture_num) { HapContext *ctx = avctx->priv_data; AVFrame *frame = arg; @@ -295,70 +299,118 @@ static int decompress_texture_thread(AVCodecContext *avctx, void *arg, uint8_t *p = frame->data[0] + y * frame->linesize[0] * TEXTURE_BLOCK_H; int off = y * w_block; for (x = 0; x < w_block; x++) { - ctx->tex_fun(p + x * 16, frame->linesize[0], - d + (off + x) * ctx->tex_rat); + if (texture_num == 0) { + ctx->tex_fun(p + x * 4 * ctx->uncompress_pix_size, frame->linesize[0], + d + (off + x) * ctx->tex_rat); + } else { + ctx->tex_fun2(p + x * 4 * ctx->uncompress_pix_size, frame->linesize[0], + d + (off + x) * ctx->tex_rat2); + } } } return 0; } +static int decompress_texture_thread(AVCodecContext *avctx, void *arg, + int slice, int thread_nb) +{ + return decompress_texture_thread_internal(avctx, arg, slice, thread_nb, 0); +} + +static int decompress_texture2_thread(AVCodecContext *avctx, void *arg, + int slice, int thread_nb) +{ + return decompress_texture_thread_internal(avctx, arg, slice, thread_nb, 1); +} + static int hap_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { HapContext *ctx = avctx->priv_data; ThreadFrame tframe; - int ret, i; + int ret, i, t; int tex_size; + int section_size; + enum HapSectionType section_type; + int start_texture_section = 0; + int tex_rat[2] = {0, 0}; bytestream2_init(&ctx->gbc, avpkt->data, avpkt->size); - /* Check for section header */ - ret = hap_parse_frame_header(avctx); - if (ret < 0) - return ret; + tex_rat[0] = ctx->tex_rat; + + /* check for multi texture header */ + if (ctx->texture_count == 2) { + ret = parse_section_header(&ctx->gbc, §ion_size, §ion_type); + if (ret != 0) + return ret; + if ((section_type & 0x0F) != 0x0D) { + av_log(avctx, AV_LOG_ERROR, "Invalid section type in 2 textures mode %#04x.\n", section_type); + return AVERROR_INVALIDDATA; + } + start_texture_section = 4; + tex_rat[1] = ctx->tex_rat2; + } /* Get the output frame ready to receive data */ tframe.f = data; ret = ff_thread_get_buffer(avctx, &tframe, 0); if (ret < 0) return ret; - if (avctx->codec->update_thread_context) - ff_thread_finish_setup(avctx); - /* Unpack the DXT texture */ - if (hap_can_use_tex_in_place(ctx)) { - /* Only DXTC texture compression in a contiguous block */ - ctx->tex_data = ctx->gbc.buffer; - tex_size = bytestream2_get_bytes_left(&ctx->gbc); - } else { - /* Perform the second-stage decompression */ - ret = av_reallocp(&ctx->tex_buf, ctx->tex_size); + for (t = 0; t < ctx->texture_count; t++) { + bytestream2_seek(&ctx->gbc, start_texture_section, SEEK_SET); + + /* Check for section header */ + ret = hap_parse_frame_header(avctx); if (ret < 0) return ret; - avctx->execute2(avctx, decompress_chunks_thread, NULL, - ctx->chunk_results, ctx->chunk_count); + start_texture_section += ctx->texture_section_size + 4; - for (i = 0; i < ctx->chunk_count; i++) { - if (ctx->chunk_results[i] < 0) - return ctx->chunk_results[i]; + if (avctx->codec->update_thread_context) + ff_thread_finish_setup(avctx); + + /* Unpack the DXT texture */ + if (hap_can_use_tex_in_place(ctx)) { + /* Only DXTC texture compression in a contiguous block */ + ctx->tex_data = ctx->gbc.buffer; + tex_size = FFMIN(ctx->texture_section_size, bytestream2_get_bytes_left(&ctx->gbc)); + } else { + /* Perform the second-stage decompression */ + ret = av_reallocp(&ctx->tex_buf, ctx->tex_size); + if (ret < 0) + return ret; + + avctx->execute2(avctx, decompress_chunks_thread, NULL, + ctx->chunk_results, ctx->chunk_count); + + for (i = 0; i < ctx->chunk_count; i++) { + if (ctx->chunk_results[i] < 0) + return ctx->chunk_results[i]; + } + + ctx->tex_data = ctx->tex_buf; + tex_size = ctx->tex_size; } - ctx->tex_data = ctx->tex_buf; - tex_size = ctx->tex_size; - } + if (tex_size < (avctx->coded_width / TEXTURE_BLOCK_W) + *(avctx->coded_height / TEXTURE_BLOCK_H) + *tex_rat[t]) { + av_log(avctx, AV_LOG_ERROR, "Insufficient data\n"); + return AVERROR_INVALIDDATA; + } - if (tex_size < (avctx->coded_width / TEXTURE_BLOCK_W) - *(avctx->coded_height / TEXTURE_BLOCK_H) - *ctx->tex_rat) { - av_log(avctx, AV_LOG_ERROR, "Insufficient data\n"); - return AVERROR_INVALIDDATA; + /* Use the decompress function on the texture, one block per thread */ + if (t == 0){ + avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, ctx->slice_count); + } else{ + tframe.f = data; + avctx->execute2(avctx, decompress_texture2_thread, tframe.f, NULL, ctx->slice_count); + } } - /* Use the decompress function on the texture, one block per thread */ - avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, ctx->slice_count); - /* Frame is ready to be output */ tframe.f->pict_type = AV_PICTURE_TYPE_I; tframe.f->key_frame = 1; @@ -385,6 +437,9 @@ static av_cold int hap_init(AVCodecContext *avctx) ff_texturedsp_init(&ctx->dxtc); + ctx->texture_count = 1; + ctx->uncompress_pix_size = 4; + switch (avctx->codec_tag) { case MKTAG('H','a','p','1'): texture_name = "DXT1"; @@ -407,12 +462,19 @@ static av_cold int hap_init(AVCodecContext *avctx) case MKTAG('H','a','p','A'): texture_name = "RGTC1"; ctx->tex_rat = 8; - ctx->tex_fun = ctx->dxtc.rgtc1u_block; - avctx->pix_fmt = AV_PIX_FMT_RGB0; + ctx->tex_fun = ctx->dxtc.rgtc1u_gray_block; + avctx->pix_fmt = AV_PIX_FMT_GRAY8; + ctx->uncompress_pix_size = 1; break; case MKTAG('H','a','p','M'): - avpriv_report_missing_feature(avctx, "HapQAlpha"); - return AVERROR_PATCHWELCOME; + texture_name = "DXT5-YCoCg-scaled / RGTC1"; + ctx->tex_rat = 16; + ctx->tex_rat2 = 8; + ctx->tex_fun = ctx->dxtc.dxt5ys_block; + ctx->tex_fun2 = ctx->dxtc.rgtc1u_alpha_block; + avctx->pix_fmt = AV_PIX_FMT_RGBA; + ctx->texture_count = 2; + break; default: return AVERROR_DECODER_NOT_FOUND; } diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h index f0fb919a7..2f20db828 100644 --- a/libavcodec/hevc.h +++ b/libavcodec/hevc.h @@ -74,19 +74,60 @@ enum HEVCSliceType { HEVC_SLICE_I = 2, }; -/** - * 7.4.2.1 - */ -#define HEVC_MAX_SUB_LAYERS 7 -#define HEVC_MAX_VPS_COUNT 16 -#define HEVC_MAX_SPS_COUNT 32 -#define HEVC_MAX_PPS_COUNT 256 -#define HEVC_MAX_SHORT_TERM_RPS_COUNT 64 -#define HEVC_MAX_CU_SIZE 128 +enum { + // 7.4.3.1: vps_max_layers_minus1 is in [0, 62]. + HEVC_MAX_LAYERS = 63, + // 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6]. + HEVC_MAX_SUB_LAYERS = 7, + // 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023]. + HEVC_MAX_LAYER_SETS = 1024, -#define HEVC_MAX_REFS 16 -#define HEVC_MAX_DPB_SIZE 16 // A.4.1 + // 7.4.2.1: vps_video_parameter_set_id is u(4). + HEVC_MAX_VPS_COUNT = 16, + // 7.4.3.2.1: sps_seq_parameter_set_id is in [0, 15]. + HEVC_MAX_SPS_COUNT = 16, + // 7.4.3.3.1: pps_pic_parameter_set_id is in [0, 63]. + HEVC_MAX_PPS_COUNT = 64, + + // A.4.2: MaxDpbSize is bounded above by 16. + HEVC_MAX_DPB_SIZE = 16, + // 7.4.3.1: vps_max_dec_pic_buffering_minus1[i] is in [0, MaxDpbSize - 1]. + HEVC_MAX_REFS = HEVC_MAX_DPB_SIZE, + + // 7.4.3.2.1: num_short_term_ref_pic_sets is in [0, 64]. + HEVC_MAX_SHORT_TERM_REF_PIC_SETS = 64, + // 7.4.3.2.1: num_long_term_ref_pics_sps is in [0, 32]. + HEVC_MAX_LONG_TERM_REF_PICS = 32, + + // A.3: all profiles require that CtbLog2SizeY is in [4, 6]. + HEVC_MIN_LOG2_CTB_SIZE = 4, + HEVC_MAX_LOG2_CTB_SIZE = 6, + + // E.3.2: cpb_cnt_minus1[i] is in [0, 31]. + HEVC_MAX_CPB_CNT = 32, + + // A.4.1: in table A.6 the highest level allows a MaxLumaPs of 35 651 584. + HEVC_MAX_LUMA_PS = 35651584, + // A.4.1: pic_width_in_luma_samples and pic_height_in_luma_samples are + // constrained to be not greater than sqrt(MaxLumaPs * 8). Hence height/ + // width are bounded above by sqrt(8 * 35651584) = 16888.2 samples. + HEVC_MAX_WIDTH = 16888, + HEVC_MAX_HEIGHT = 16888, + + // A.4.1: table A.6 allows at most 22 tile rows for any level. + HEVC_MAX_TILE_ROWS = 22, + // A.4.1: table A.6 allows at most 20 tile columns for any level. + HEVC_MAX_TILE_COLUMNS = 20, + + // 7.4.7.1: in the worst case (tiles_enabled_flag and + // entropy_coding_sync_enabled_flag are both set), entry points can be + // placed at the beginning of every Ctb row in every tile, giving an + // upper bound of (num_tile_columns_minus1 + 1) * PicHeightInCtbsY - 1. + // Only a stream with very high resolution and perverse parameters could + // get near that, though, so set a lower limit here with the maximum + // possible value for 4K video (at most 135 16x16 Ctb rows). + HEVC_MAX_ENTRY_POINT_OFFSETS = HEVC_MAX_TILE_COLUMNS * 135, +}; -#define HEVC_MAX_LOG2_CTB_SIZE 6 #endif /* AVCODEC_HEVC_H */ diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c index 853fd3f72..5b5da1165 100644 --- a/libavcodec/hevc_cabac.c +++ b/libavcodec/hevc_cabac.c @@ -646,8 +646,10 @@ int ff_hevc_cu_qp_delta_abs(HEVCContext *s) suffix_val += 1 << k; k++; } - if (k == CABAC_MAX_BIN) + if (k == CABAC_MAX_BIN) { av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k); + return AVERROR_INVALIDDATA; + } while (k--) suffix_val += get_cabac_bypass(&s->HEVClc->cc) << k; diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c index b53f4cc72..6b9824088 100644 --- a/libavcodec/hevc_filter.c +++ b/libavcodec/hevc_filter.c @@ -842,9 +842,20 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0, void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size) { int x_end = x >= s->ps.sps->width - ctb_size; - if (s->avctx->skip_loop_filter < AVDISCARD_ALL) + int skip = 0; + if (s->avctx->skip_loop_filter >= AVDISCARD_ALL || + (s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && !IS_IDR(s)) || + (s->avctx->skip_loop_filter >= AVDISCARD_NONINTRA && + s->sh.slice_type != HEVC_SLICE_I) || + (s->avctx->skip_loop_filter >= AVDISCARD_BIDIR && + s->sh.slice_type == HEVC_SLICE_B) || + (s->avctx->skip_loop_filter >= AVDISCARD_NONREF && + ff_hevc_nal_is_nonref(s->nal_unit_type))) + skip = 1; + + if (!skip) deblocking_filter_CTB(s, x, y); - if (s->ps.sps->sao_enabled) { + if (s->ps.sps->sao_enabled && !skip) { int y_end = y >= s->ps.sps->height - ctb_size; if (y && x) sao_filter_CTB(s, x - ctb_size, y - ctb_size); diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c index a8f7876b5..fd0dbd9a5 100644 --- a/libavcodec/hevc_mvs.c +++ b/libavcodec/hevc_mvs.c @@ -482,7 +482,7 @@ void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW, { int singleMCLFlag = 0; int nCS = 1 << log2_cb_size; - LOCAL_ALIGNED(4, MvField, mergecand_list, [MRG_MAX_NUM_CANDS]); + MvField mergecand_list[MRG_MAX_NUM_CANDS]; int nPbW2 = nPbW; int nPbH2 = nPbH; HEVCLocalContext *lc = s->HEVClc; diff --git a/libavcodec/hevc_parse.c b/libavcodec/hevc_parse.c index 1122a60af..b1b27eef0 100644 --- a/libavcodec/hevc_parse.c +++ b/libavcodec/hevc_parse.c @@ -22,7 +22,7 @@ #include "hevc_parse.h" static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets *ps, - HEVCSEIContext *sei, int is_nalff, int nal_length_size, + HEVCSEI *sei, int is_nalff, int nal_length_size, int err_recognition, int apply_defdispwin, void *logctx) { int i; @@ -75,7 +75,7 @@ done: } int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps, - HEVCSEIContext *sei, int *is_nalff, int *nal_length_size, + HEVCSEI *sei, int *is_nalff, int *nal_length_size, int err_recognition, int apply_defdispwin, void *logctx) { int ret = 0; diff --git a/libavcodec/hevc_parse.h b/libavcodec/hevc_parse.h index 02e1d5b32..4ab96ab1c 100644 --- a/libavcodec/hevc_parse.h +++ b/libavcodec/hevc_parse.h @@ -30,7 +30,7 @@ #include "hevc_sei.h" int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps, - HEVCSEIContext *sei, int *is_nalff, int *nal_length_size, + HEVCSEI *sei, int *is_nalff, int *nal_length_size, int err_recognition, int apply_defdispwin, void *logctx); #endif /* AVCODEC_HEVC_PARSE_H */ diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c index dc63c6b95..ff7e8a49d 100644 --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc_parser.c @@ -40,7 +40,7 @@ typedef struct HEVCParserContext { H2645Packet pkt; HEVCParamSets ps; - HEVCSEIContext sei; + HEVCSEI sei; SliceHeader sh; int parsed_extradata; @@ -54,7 +54,7 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, { HEVCParserContext *ctx = s->priv_data; HEVCParamSets *ps = &ctx->ps; - HEVCSEIContext *sei = &ctx->sei; + HEVCSEI *sei = &ctx->sei; SliceHeader *sh = &ctx->sh; GetBitContext *gb = &nal->gb; const HEVCWindow *ow; @@ -180,7 +180,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, { HEVCParserContext *ctx = s->priv_data; HEVCParamSets *ps = &ctx->ps; - HEVCSEIContext *sei = &ctx->sei; + HEVCSEI *sei = &ctx->sei; int is_global = buf == avctx->extradata; int ret, i; diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c index 902917d4d..a4f7ed60f 100644 --- a/libavcodec/hevc_ps.c +++ b/libavcodec/hevc_ps.c @@ -1061,7 +1061,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, } sps->nb_st_rps = get_ue_golomb_long(gb); - if (sps->nb_st_rps > HEVC_MAX_SHORT_TERM_RPS_COUNT) { + if (sps->nb_st_rps > HEVC_MAX_SHORT_TERM_REF_PIC_SETS) { av_log(avctx, AV_LOG_ERROR, "Too many short term RPS: %d.\n", sps->nb_st_rps); return AVERROR_INVALIDDATA; @@ -1075,8 +1075,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->long_term_ref_pics_present_flag = get_bits1(gb); if (sps->long_term_ref_pics_present_flag) { sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb); - if (sps->num_long_term_ref_pics_sps > 31U) { - av_log(avctx, AV_LOG_ERROR, "num_long_term_ref_pics_sps %d is out of range.\n", + if (sps->num_long_term_ref_pics_sps > HEVC_MAX_LONG_TERM_REF_PICS) { + av_log(avctx, AV_LOG_ERROR, "Too many long term ref pics: %d.\n", sps->num_long_term_ref_pics_sps); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/hevc_ps.h b/libavcodec/hevc_ps.h index 76f8eb31e..477ee4299 100644 --- a/libavcodec/hevc_ps.h +++ b/libavcodec/hevc_ps.h @@ -254,14 +254,14 @@ typedef struct HEVCSPS { ScalingList scaling_list; unsigned int nb_st_rps; - ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_RPS_COUNT]; + ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; uint8_t amp_enabled_flag; uint8_t sao_enabled; uint8_t long_term_ref_pics_present_flag; - uint16_t lt_ref_pic_poc_lsb_sps[32]; - uint8_t used_by_curr_pic_lt_sps_flag[32]; + uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; + uint8_t used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; uint8_t num_long_term_ref_pics_sps; struct { diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c index d0f9966a2..c59bd4321 100644 --- a/libavcodec/hevc_sei.c +++ b/libavcodec/hevc_sei.c @@ -95,10 +95,11 @@ static int decode_nal_sei_frame_packing_arrangement(HEVCSEIFramePacking *s, GetB s->quincunx_subsampling = get_bits1(gb); s->content_interpretation_type = get_bits(gb, 6); - // the following skips spatial_flipping_flag frame0_flipped_flag - // field_views_flag current_frame_is_frame0_flag - // frame0_self_contained_flag frame1_self_contained_flag - skip_bits(gb, 6); + // spatial_flipping_flag, frame0_flipped_flag, field_views_flag + skip_bits(gb, 3); + s->current_frame_is_frame0_flag = get_bits1(gb); + // frame0_self_contained_flag, frame1_self_contained_flag + skip_bits(gb, 2); if (!s->quincunx_subsampling && s->arrangement_type != 5) skip_bits(gb, 16); // frame[01]_grid_position_[xy] @@ -124,7 +125,7 @@ static int decode_nal_sei_display_orientation(HEVCSEIDisplayOrientation *s, GetB return 0; } -static int decode_nal_sei_pic_timing(HEVCSEIContext *s, GetBitContext *gb, const HEVCParamSets *ps, +static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, const HEVCParamSets *ps, void *logctx, int size) { HEVCSEIPictureTiming *h = &s->picture_timing; @@ -205,7 +206,7 @@ static int decode_registered_user_data_closed_caption(HEVCSEIA53Caption *s, GetB return 0; } -static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEIContext *s, GetBitContext *gb, +static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEI *s, GetBitContext *gb, int size) { uint32_t country_code; @@ -236,7 +237,7 @@ static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEIContext *s, GetB return 0; } -static int decode_nal_sei_active_parameter_sets(HEVCSEIContext *s, GetBitContext *gb, void *logctx) +static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, void *logctx) { int num_sps_ids_minus1; int i; @@ -272,8 +273,8 @@ static int decode_nal_sei_alternative_transfer(HEVCSEIAlternativeTransfer *s, Ge return 0; } -static int decode_nal_sei_prefix(GetBitContext *gb, HEVCSEIContext *s, const HEVCParamSets *ps, - int type, int size, void *logctx) +static int decode_nal_sei_prefix(GetBitContext *gb, void *logctx, HEVCSEI *s, + const HEVCParamSets *ps, int type, int size) { switch (type) { case 256: // Mismatched value from HM 8.1 @@ -301,8 +302,8 @@ static int decode_nal_sei_prefix(GetBitContext *gb, HEVCSEIContext *s, const HEV } } -static int decode_nal_sei_suffix(GetBitContext *gb, HEVCSEIContext *s, - int type, int size, void *logctx) +static int decode_nal_sei_suffix(GetBitContext *gb, void *logctx, HEVCSEI *s, + int type, int size) { switch (type) { case HEVC_SEI_TYPE_DECODED_PICTURE_HASH: @@ -314,9 +315,8 @@ static int decode_nal_sei_suffix(GetBitContext *gb, HEVCSEIContext *s, } } -static int decode_nal_sei_message(GetBitContext *gb, HEVCSEIContext *s, - const HEVCParamSets *ps, int nal_unit_type, - void *logctx) +static int decode_nal_sei_message(GetBitContext *gb, void *logctx, HEVCSEI *s, + const HEVCParamSets *ps, int nal_unit_type) { int payload_type = 0; int payload_size = 0; @@ -324,18 +324,22 @@ static int decode_nal_sei_message(GetBitContext *gb, HEVCSEIContext *s, av_log(logctx, AV_LOG_DEBUG, "Decoding SEI\n"); while (byte == 0xFF) { + if (get_bits_left(gb) < 16 || payload_type > INT_MAX - 255) + return AVERROR_INVALIDDATA; byte = get_bits(gb, 8); payload_type += byte; } byte = 0xFF; while (byte == 0xFF) { + if (get_bits_left(gb) < 8 + 8LL*payload_size) + return AVERROR_INVALIDDATA; byte = get_bits(gb, 8); payload_size += byte; } if (nal_unit_type == HEVC_NAL_SEI_PREFIX) { - return decode_nal_sei_prefix(gb, s, ps, payload_type, payload_size, logctx); + return decode_nal_sei_prefix(gb, logctx, s, ps, payload_type, payload_size); } else { /* nal_unit_type == NAL_SEI_SUFFIX */ - return decode_nal_sei_suffix(gb, s, payload_type, payload_size, logctx); + return decode_nal_sei_suffix(gb, logctx, s, payload_type, payload_size); } } @@ -344,20 +348,20 @@ static int more_rbsp_data(GetBitContext *gb) return get_bits_left(gb) > 0 && show_bits(gb, 8) != 0x80; } -int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEIContext *s, +int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, const HEVCParamSets *ps, int type) { int ret; do { - ret = decode_nal_sei_message(gb, s, ps, type, logctx); + ret = decode_nal_sei_message(gb, logctx, s, ps, type); if (ret < 0) return ret; } while (more_rbsp_data(gb)); return 1; } -void ff_hevc_reset_sei(HEVCSEIContext *s) +void ff_hevc_reset_sei(HEVCSEI *s) { s->a53_caption.a53_caption_size = 0; av_freep(&s->a53_caption.a53_caption); diff --git a/libavcodec/hevc_sei.h b/libavcodec/hevc_sei.h index 1b522227e..e92da25bb 100644 --- a/libavcodec/hevc_sei.h +++ b/libavcodec/hevc_sei.h @@ -23,8 +23,6 @@ #include -#include "libavutil/md5.h" - #include "get_bits.h" /** @@ -60,7 +58,6 @@ typedef enum { } HEVC_SEI_Type; typedef struct HEVCSEIPictureHash { - struct AVMD5 *md5_ctx; uint8_t md5[3][16]; uint8_t is_md5; } HEVCSEIPictureHash; @@ -70,6 +67,7 @@ typedef struct HEVCSEIFramePacking { int arrangement_type; int content_interpretation_type; int quincunx_subsampling; + int current_frame_is_frame0_flag; } HEVCSEIFramePacking; typedef struct HEVCSEIDisplayOrientation { @@ -106,7 +104,7 @@ typedef struct HEVCSEIAlternativeTransfer { int preferred_transfer_characteristics; } HEVCSEIAlternativeTransfer; -typedef struct HEVCSEIContext { +typedef struct HEVCSEI { HEVCSEIPictureHash picture_hash; HEVCSEIFramePacking frame_packing; HEVCSEIDisplayOrientation display_orientation; @@ -116,11 +114,11 @@ typedef struct HEVCSEIContext { HEVCSEIContentLight content_light; int active_seq_parameter_set_id; HEVCSEIAlternativeTransfer alternative_transfer; -} HEVCSEIContext; +} HEVCSEI; struct HEVCParamSets; -int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEIContext *s, +int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, const struct HEVCParamSets *ps, int type); /** @@ -130,6 +128,6 @@ int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEIContext *s, * * @param s HEVCContext. */ -void ff_hevc_reset_sei(HEVCSEIContext *s); +void ff_hevc_reset_sei(HEVCSEI *s); #endif /* AVCODEC_HEVC_SEI_H */ diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 2e4add2ae..4bfae8c12 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -41,6 +41,7 @@ #include "hevc_data.h" #include "hevc_parse.h" #include "hevcdec.h" +#include "hwaccel.h" #include "profiles.h" const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 }; @@ -354,6 +355,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \ CONFIG_HEVC_D3D11VA_HWACCEL * 2 + \ + CONFIG_HEVC_NVDEC_HWACCEL + \ CONFIG_HEVC_VAAPI_HWACCEL + \ CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \ CONFIG_HEVC_VDPAU_HWACCEL) @@ -375,6 +377,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #if CONFIG_HEVC_VDPAU_HWACCEL *fmt++ = AV_PIX_FMT_VDPAU; #endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; +#endif #if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; #endif @@ -392,6 +397,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif break; } @@ -503,13 +511,14 @@ static int hls_slice_header(HEVCContext *s) } ff_hevc_clear_refs(s); + ret = set_sps(s, sps, sps->pix_fmt); + if (ret < 0) + return ret; + pix_fmt = get_format(s, sps); if (pix_fmt < 0) return pix_fmt; - - ret = set_sps(s, sps, pix_fmt); - if (ret < 0) - return ret; + s->avctx->pix_fmt = pix_fmt; s->seq_decode = (s->seq_decode + 1) & 0xff; s->max_ra = INT_MAX; @@ -2638,6 +2647,13 @@ static int set_side_data(HEVCContext *s) if (s->sei.frame_packing.content_interpretation_type == 2) stereo->flags = AV_STEREO3D_FLAG_INVERT; + + if (s->sei.frame_packing.arrangement_type == 5) { + if (s->sei.frame_packing.current_frame_is_frame0_flag) + stereo->view = AV_STEREO3D_VIEW_LEFT; + else + stereo->view = AV_STEREO3D_VIEW_RIGHT; + } } if (s->sei.display_orientation.present && @@ -2816,23 +2832,55 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) switch (s->nal_unit_type) { case HEVC_NAL_VPS: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_vps(gb, s->avctx, &s->ps); if (ret < 0) goto fail; break; case HEVC_NAL_SPS: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_sps(gb, s->avctx, &s->ps, s->apply_defdispwin); if (ret < 0) goto fail; break; case HEVC_NAL_PPS: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_pps(gb, s->avctx, &s->ps); if (ret < 0) goto fail; break; case HEVC_NAL_SEI_PREFIX: case HEVC_NAL_SEI_SUFFIX: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_sei(gb, s->avctx, &s->sei, &s->ps, s->nal_unit_type); if (ret < 0) goto fail; @@ -2857,6 +2905,13 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) if (ret < 0) return ret; + if ( + (s->avctx->skip_frame >= AVDISCARD_BIDIR && s->sh.slice_type == HEVC_SLICE_B) || + (s->avctx->skip_frame >= AVDISCARD_NONINTRA && s->sh.slice_type != HEVC_SLICE_I) || + (s->avctx->skip_frame >= AVDISCARD_NONKEY && !IS_IDR(s))) { + break; + } + if (s->sh.first_slice_in_pic_flag) { if (s->max_ra == INT_MAX) { if (s->nal_unit_type == HEVC_NAL_CRA_NUT || IS_BLA(s)) { @@ -2980,7 +3035,14 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) /* decode the NAL units */ for (i = 0; i < s->pkt.nb_nals; i++) { - ret = decode_nal_unit(s, &s->pkt.nals[i]); + H2645NAL *nal = &s->pkt.nals[i]; + + if (s->avctx->skip_frame >= AVDISCARD_ALL || + (s->avctx->skip_frame >= AVDISCARD_NONREF + && ff_hevc_nal_is_nonref(nal->type))) + continue; + + ret = decode_nal_unit(s, nal); if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Error parsing NAL unit #%d.\n", i); @@ -3035,7 +3097,7 @@ static int verify_md5(HEVCContext *s, AVFrame *frame) int h = (i == 1 || i == 2) ? (height >> desc->log2_chroma_h) : height; uint8_t md5[16]; - av_md5_init(s->sei.picture_hash.md5_ctx); + av_md5_init(s->md5_ctx); for (j = 0; j < h; j++) { const uint8_t *src = frame->data[i] + j * frame->linesize[i]; #if HAVE_BIGENDIAN @@ -3045,9 +3107,9 @@ static int verify_md5(HEVCContext *s, AVFrame *frame) src = s->checksum_buf; } #endif - av_md5_update(s->sei.picture_hash.md5_ctx, src, w << pixel_shift); + av_md5_update(s->md5_ctx, src, w << pixel_shift); } - av_md5_final(s->sei.picture_hash.md5_ctx, md5); + av_md5_final(s->md5_ctx, md5); if (!memcmp(md5, s->sei.picture_hash.md5[i], 16)) { av_log (s->avctx, AV_LOG_DEBUG, "plane %d - correct ", i); @@ -3200,7 +3262,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) pic_arrays_free(s); - av_freep(&s->sei.picture_hash.md5_ctx); + av_freep(&s->md5_ctx); av_freep(&s->cabac_state); @@ -3275,8 +3337,8 @@ static av_cold int hevc_init_context(AVCodecContext *avctx) s->max_ra = INT_MAX; - s->sei.picture_hash.md5_ctx = av_md5_alloc(); - if (!s->sei.picture_hash.md5_ctx) + s->md5_ctx = av_md5_alloc(); + if (!s->md5_ctx) goto fail; ff_bswapdsp_init(&s->bdsp); @@ -3470,4 +3532,28 @@ AVCodec ff_hevc_decoder = { AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_HEVC_DXVA2_HWACCEL + HWACCEL_DXVA2(hevc), +#endif +#if CONFIG_HEVC_D3D11VA_HWACCEL + HWACCEL_D3D11VA(hevc), +#endif +#if CONFIG_HEVC_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(hevc), +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + HWACCEL_NVDEC(hevc), +#endif +#if CONFIG_HEVC_VAAPI_HWACCEL + HWACCEL_VAAPI(hevc), +#endif +#if CONFIG_HEVC_VDPAU_HWACCEL + HWACCEL_VDPAU(hevc), +#endif +#if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(hevc), +#endif + NULL + }, }; diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h index 293beb708..b311edc8a 100644 --- a/libavcodec/hevcdec.h +++ b/libavcodec/hevcdec.h @@ -26,6 +26,7 @@ #include #include "libavutil/buffer.h" +#include "libavutil/md5.h" #include "avcodec.h" #include "bswapdsp.h" @@ -363,7 +364,7 @@ typedef struct HEVCLocalContext { DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; /* The extended size between the new edge emu buffer is abused by SAO */ DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer2)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; - DECLARE_ALIGNED(32, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]); + DECLARE_ALIGNED(32, int16_t, tmp)[MAX_PB_SIZE * MAX_PB_SIZE]; int ct_depth; CodingUnit cu; @@ -405,6 +406,8 @@ typedef struct HEVCContext { uint8_t *sao_pixel_buffer_v[3]; HEVCParamSets ps; + HEVCSEI sei; + struct AVMD5 *md5_ctx; AVBufferPool *tab_mvf_pool; AVBufferPool *rpl_tab_pool; @@ -480,8 +483,6 @@ typedef struct HEVCContext { int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4) int nuh_layer_id; - - HEVCSEIContext sei; } HEVCContext; /** @@ -547,6 +548,26 @@ int ff_hevc_frame_nb_refs(HEVCContext *s); int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc); +static av_always_inline int ff_hevc_nal_is_nonref(enum HEVCNALUnitType type) +{ + switch (type) { + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TSA_N: + case HEVC_NAL_STSA_N: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RASL_N: + case HEVC_NAL_VCL_N10: + case HEVC_NAL_VCL_N12: + case HEVC_NAL_VCL_N14: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_N_LP: + return 1; + break; + default: break; + } + return 0; +} + /** * Find next frame in output order and put a reference to it in frame. * @return 1 if a frame was output, 0 otherwise diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevcdsp.c index 76ae72b6d..957e40d5f 100644 --- a/libavcodec/hevcdsp.c +++ b/libavcodec/hevcdsp.c @@ -91,7 +91,7 @@ static const int8_t transform[32][32] = { 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 }, }; -DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][4]) = { +DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters)[7][4] = { { -2, 58, 10, -2}, { -4, 54, 16, -2}, { -6, 46, 28, -4}, @@ -101,7 +101,7 @@ DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][4]) = { { -2, 10, 58, -2}, }; -DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters[3][16]) = { +DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters)[3][16] = { { -1, 4,-10, 58, 17, -5, 1, 0, -1, 4,-10, 58, 17, -5, 1, 0}, { -1, 4,-11, 40, 40,-11, 4, -1, -1, 4,-11, 40, 40,-11, 4, -1}, { 0, 1, -5, 17, 58,-10, 4, -1, 0, 1, -5, 17, 58,-10, 4, -1} @@ -257,12 +257,12 @@ int i = 0; break; } + if (ARCH_ARM) + ff_hevc_dsp_init_arm(hevcdsp, bit_depth); if (ARCH_PPC) ff_hevc_dsp_init_ppc(hevcdsp, bit_depth); if (ARCH_X86) ff_hevc_dsp_init_x86(hevcdsp, bit_depth); - if (ARCH_ARM) - ff_hevcdsp_init_arm(hevcdsp, bit_depth); if (ARCH_MIPS) ff_hevc_dsp_init_mips(hevcdsp, bit_depth); } diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h index dc48ebca1..0ae67cba8 100644 --- a/libavcodec/hevcdsp.h +++ b/libavcodec/hevcdsp.h @@ -127,8 +127,9 @@ void ff_hevc_dsp_init(HEVCDSPContext *hpc, int bit_depth); extern const int8_t ff_hevc_epel_filters[7][4]; extern const int8_t ff_hevc_qpel_filters[3][16]; +void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_ppc(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth); -void ff_hevcdsp_init_arm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth); + #endif /* AVCODEC_HEVCDSP_H */ diff --git a/libavcodec/hevcdsp_template.c b/libavcodec/hevcdsp_template.c index e09c66175..56cd9e605 100644 --- a/libavcodec/hevcdsp_template.c +++ b/libavcodec/hevcdsp_template.c @@ -121,7 +121,7 @@ static void FUNC(dequant)(int16_t *coeffs, int16_t log2_size) } else { for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { - *coeffs = *coeffs << -shift; + *coeffs = *(uint16_t*)coeffs << -shift; coeffs++; } } @@ -915,7 +915,7 @@ static void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; @@ -970,7 +970,7 @@ static void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; @@ -1051,7 +1051,7 @@ static void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uin for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); tmp += MAX_PB_SIZE; dst += dststride; src2 += MAX_PB_SIZE; @@ -1355,7 +1355,7 @@ static void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; @@ -1407,7 +1407,7 @@ static void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 89639b75d..8be752844 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -52,42 +52,30 @@ static inline int sub_left_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *src, int w, int left) { int i; + int min_width = FFMIN(w, 32); + if (s->bps <= 8) { - if (w < 32) { - for (i = 0; i < w; i++) { - const int temp = src[i]; - dst[i] = temp - left; - left = temp; - } - return left; - } else { - for (i = 0; i < 32; i++) { - const int temp = src[i]; - dst[i] = temp - left; - left = temp; - } - s->llvidencdsp.diff_bytes(dst + 32, src + 32, src + 31, w - 32); - return src[w-1]; + for (i = 0; i < min_width; i++) { /* scalar loop before dsp call */ + const int temp = src[i]; + dst[i] = temp - left; + left = temp; } + if (w < 32) + return left; + s->llvidencdsp.diff_bytes(dst + 32, src + 32, src + 31, w - 32); + return src[w-1]; } else { const uint16_t *src16 = (const uint16_t *)src; uint16_t *dst16 = ( uint16_t *)dst; - if (w < 32) { - for (i = 0; i < w; i++) { - const int temp = src16[i]; - dst16[i] = temp - left; - left = temp; - } - return left; - } else { - for (i = 0; i < 16; i++) { - const int temp = src16[i]; - dst16[i] = temp - left; - left = temp; - } - s->hencdsp.diff_int16(dst16 + 16, src16 + 16, src16 + 15, s->n - 1, w - 16); - return src16[w-1]; + for (i = 0; i < min_width; i++) { /* scalar loop before dsp call */ + const int temp = src16[i]; + dst16[i] = temp - left; + left = temp; } + if (w < 32) + return left; + s->hencdsp.diff_int16(dst16 + 32, src16 + 32, src16 + 31, s->n - 1, w - 32); + return src16[w-1]; } } @@ -98,12 +86,13 @@ static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst, { int i; int r, g, b, a; + int min_width = FFMIN(w, 8); r = *red; g = *green; b = *blue; a = *alpha; - for (i = 0; i < FFMIN(w, 4); i++) { + for (i = 0; i < min_width; i++) { const int rt = src[i * 4 + R]; const int gt = src[i * 4 + G]; const int bt = src[i * 4 + B]; @@ -118,7 +107,7 @@ static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst, a = at; } - s->llvidencdsp.diff_bytes(dst + 16, src + 16, src + 12, w * 4 - 16); + s->llvidencdsp.diff_bytes(dst + 32, src + 32, src + 32 - 4, w * 4 - 32); *red = src[(w - 1) * 4 + R]; *green = src[(w - 1) * 4 + G]; diff --git a/libavcodec/hwaccel.h b/libavcodec/hwaccel.h index 124fbbf1f..3aaa92571 100644 --- a/libavcodec/hwaccel.h +++ b/libavcodec/hwaccel.h @@ -19,6 +19,66 @@ #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/libavcodec/hwaccels.h b/libavcodec/hwaccels.h new file mode 100644 index 000000000..fcfe4e088 --- /dev/null +++ b/libavcodec/hwaccels.h @@ -0,0 +1,76 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_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/libavcodec/internal.h b/libavcodec/internal.h index faa923c11..16bd10128 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -76,22 +76,20 @@ #endif -#if !FF_API_QUANT_BIAS #define FF_DEFAULT_QUANT_BIAS 999999 -#endif -#if !FF_API_QSCALE_TYPE #define FF_QSCALE_TYPE_MPEG1 0 #define FF_QSCALE_TYPE_MPEG2 1 #define FF_QSCALE_TYPE_H264 2 #define FF_QSCALE_TYPE_VP56 3 -#endif #define FF_SANE_NB_CHANNELS 64U #define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1) -#if HAVE_SIMD_ALIGN_32 +#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 @@ -245,13 +243,6 @@ int ff_init_buffer_info(AVCodecContext *s, AVFrame *frame); void ff_color_frame(AVFrame *frame, const int color[4]); -extern volatile int ff_avcodec_locked; -int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec); -int ff_unlock_avcodec(const AVCodec *codec); - -int avpriv_lock_avformat(void); -int avpriv_unlock_avformat(void); - /** * Maximum size in bytes of extradata. * This value was chosen such that every bit of the buffer is @@ -373,14 +364,16 @@ int ff_set_sar(AVCodecContext *avctx, AVRational sar); int ff_side_data_update_matrix_encoding(AVFrame *frame, enum AVMatrixEncoding matrix_encoding); -#if FF_API_MERGE_SD -int ff_packet_split_and_drop_side_data(AVPacket *pkt); -#endif - /** * 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); @@ -417,4 +410,10 @@ int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, */ int64_t ff_guess_coded_bitrate(AVCodecContext *avctx); +#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/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index c8d386173..3e542af3c 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -69,6 +69,7 @@ #include "bytestream.h" #include "jpeg2000.h" #include "libavutil/common.h" +#include "libavutil/pixdesc.h" #include "libavutil/opt.h" #define NMSEDEC_BITS 7 @@ -662,7 +663,8 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 bpno = cblk->nonzerobits - 1; } - ff_mqc_initenc(&t1->mqc, cblk->data); + cblk->data[0] = 0; + ff_mqc_initenc(&t1->mqc, cblk->data + 1); for (passno = 0; bpno >= 0; passno++){ nmsedec=0; @@ -688,7 +690,8 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 cblk->npasses = passno; cblk->ninclpasses = passno; - cblk->passes[passno-1].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno-1].flushed, &cblk->passes[passno-1].flushed_len); + if (passno) + cblk->passes[passno-1].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno-1].flushed, &cblk->passes[passno-1].flushed_len); } /* tier-2 routines: */ @@ -795,7 +798,7 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in if (cblk->ninclpasses){ if (s->buf_end - s->buf < cblk->passes[cblk->ninclpasses-1].rate) return -1; - bytestream_put_buffer(&s->buf, cblk->data, cblk->passes[cblk->ninclpasses-1].rate + bytestream_put_buffer(&s->buf, cblk->data + 1, cblk->passes[cblk->ninclpasses-1].rate - cblk->passes[cblk->ninclpasses-1].flushed_len); bytestream_put_buffer(&s->buf, cblk->passes[cblk->ninclpasses-1].flushed, cblk->passes[cblk->ninclpasses-1].flushed_len); @@ -936,6 +939,12 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno } } } + if (!prec->cblk[cblkno].data) + prec->cblk[cblkno].data = av_malloc(1 + 8192); + if (!prec->cblk[cblkno].passes) + prec->cblk[cblkno].passes = av_malloc_array(JPEG2000_MAX_PASSES, sizeof (*prec->cblk[cblkno].passes)); + if (!prec->cblk[cblkno].data || !prec->cblk[cblkno].passes) + return AVERROR(ENOMEM); encode_cblk(s, &t1, prec->cblk + cblkno, tile, xx1 - xx0, yy1 - yy0, bandpos, codsty->nreslevels - reslevelno - 1); xx0 = xx1; @@ -1150,8 +1159,10 @@ FF_ENABLE_DEPRECATION_WARNINGS } else{ // planar YUV s->planar = 1; s->ncomponents = 3; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, - s->chroma_shift, s->chroma_shift + 1); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, + s->chroma_shift, s->chroma_shift + 1); + if (ret) + return ret; } ff_jpeg2000_init_tier1_luts(); diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index afeb9df27..e7f03bd0d 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -357,10 +357,8 @@ static int init_prec(Jpeg2000Band *band, comp->reslevel[reslevelno-1].coord[1][0]; } - cblk->zero = 0; cblk->lblock = 3; cblk->length = 0; - memset(cblk->lengthinc, 0, sizeof(cblk->lengthinc)); cblk->npasses = 0; } @@ -598,9 +596,21 @@ void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty) for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++) { if (band->prec) { Jpeg2000Prec *prec = band->prec + precno; + int nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; + av_freep(&prec->zerobits); av_freep(&prec->cblkincl); - av_freep(&prec->cblk); + if (prec->cblk) { + int cblkno; + for (cblkno = 0; cblkno < nb_code_blocks; cblkno ++) { + Jpeg2000Cblk *cblk = &prec->cblk[cblkno]; + av_freep(&cblk->data); + av_freep(&cblk->passes); + av_freep(&cblk->lengthinc); + av_freep(&cblk->data_start); + } + av_freep(&prec->cblk); + } } } diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index 8a022ad91..c429ca599 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -165,15 +165,15 @@ typedef struct Jpeg2000Cblk { uint8_t ninclpasses; // number coding of passes included in codestream uint8_t nonzerobits; uint16_t length; - uint16_t lengthinc[JPEG2000_MAX_PASSES]; + uint16_t *lengthinc; uint8_t nb_lengthinc; uint8_t lblock; - uint8_t zero; - uint8_t data[8192]; + uint8_t *data; + size_t data_allocated; int nb_terminations; int nb_terminationsinc; - int data_start[JPEG2000_MAX_PASSES]; - Jpeg2000Pass passes[JPEG2000_MAX_PASSES]; + int *data_start; + Jpeg2000Pass *passes; int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} } Jpeg2000Cblk; // code block diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 9a5e64e85..01fe4b394 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -949,6 +949,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) { Jpeg2000Cblk *cblk = prec->cblk + cblkno; int incl, newpasses, llen; + void *tmp; if (cblk->npasses) incl = get_bits(s, 1); @@ -988,6 +989,14 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, cblk->nb_lengthinc = 0; cblk->nb_terminationsinc = 0; + av_free(cblk->lengthinc); + cblk->lengthinc = av_mallocz_array(newpasses , sizeof(*cblk->lengthinc)); + if (!cblk->lengthinc) + return AVERROR(ENOMEM); + tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start)); + if (!tmp) + return AVERROR(ENOMEM); + cblk->data_start = tmp; do { int newpasses1 = 0; @@ -1001,10 +1010,18 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) return ret; - if (ret > sizeof(cblk->data)) { + if (ret > cblk->data_allocated) { + size_t new_size = FFMAX(2*cblk->data_allocated, ret); + void *new = av_realloc(cblk->data, new_size); + if (new) { + cblk->data = new; + cblk->data_allocated = new_size; + } + } + if (ret > cblk->data_allocated) { avpriv_request_sample(s->avctx, "Block with lengthinc greater than %"SIZE_SPECIFIER"", - sizeof(cblk->data)); + cblk->data_allocated); return AVERROR_PATCHWELCOME; } cblk->lengthinc[cblk->nb_lengthinc++] = ret; @@ -1029,9 +1046,19 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) { Jpeg2000Cblk *cblk = prec->cblk + cblkno; + if (!cblk->nb_terminationsinc && !cblk->lengthinc) + continue; for (cwsno = 0; cwsno < cblk->nb_lengthinc; cwsno ++) { + if (cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4) { + size_t new_size = FFMAX(2*cblk->data_allocated, cblk->length + cblk->lengthinc[cwsno] + 4); + void *new = av_realloc(cblk->data, new_size); + if (new) { + cblk->data = new; + cblk->data_allocated = new_size; + } + } if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc[cwsno] - || sizeof(cblk->data) < cblk->length + cblk->lengthinc[cwsno] + 4 + || cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4 ) { av_log(s->avctx, AV_LOG_ERROR, "Block length %"PRIu16" or lengthinc %d is too large, left %d\n", @@ -1050,6 +1077,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, cblk->data_start[cblk->nb_terminations] = cblk->length; } } + av_freep(&cblk->lengthinc); } } return 0; @@ -1981,7 +2009,16 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) bytestream2_get_bytes_left(&s->g) >= 8) { atom_size = bytestream2_get_be32u(&s->g); atom = bytestream2_get_be32u(&s->g); - atom_end = bytestream2_tell(&s->g) + atom_size - 8; + if (atom_size == 1) { + if (bytestream2_get_be32u(&s->g)) { + avpriv_request_sample(s->avctx, "Huge atom"); + return 0; + } + atom_size = bytestream2_get_be32u(&s->g); + atom_end = bytestream2_tell(&s->g) + atom_size - 16; + } else { + atom_end = bytestream2_tell(&s->g) + atom_size - 8; + } if (atom == JP2_CODESTREAM) return 1; @@ -2039,13 +2076,13 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) } if (colour_depth[1] <= 8) { g = bytestream2_get_byteu(&s->g) << 8 - colour_depth[1]; - r |= r >> colour_depth[1]; + g |= g >> colour_depth[1]; } else { g = bytestream2_get_be16u(&s->g) >> colour_depth[1] - 8; } if (colour_depth[2] <= 8) { b = bytestream2_get_byteu(&s->g) << 8 - colour_depth[2]; - r |= r >> colour_depth[2]; + b |= b >> colour_depth[2]; } else { b = bytestream2_get_be16u(&s->g) >> colour_depth[2] - 8; } diff --git a/libavcodec/jpeg2000dsp.c b/libavcodec/jpeg2000dsp.c index 85a12d0e9..90e73b1e2 100644 --- a/libavcodec/jpeg2000dsp.c +++ b/libavcodec/jpeg2000dsp.c @@ -64,9 +64,9 @@ static void ict_int(void *_src0, void *_src1, void *_src2, int csize) int i; for (i = 0; i < csize; i++) { - i0 = *src0 + *src2 + (((26345 * *src2) + (1 << 15)) >> 16); + i0 = *src0 + *src2 + ((int)((26345U * *src2) + (1 << 15)) >> 16); i1 = *src0 - ((int)(((unsigned)i_ict_params[1] * *src1) + (1 << 15)) >> 16) - - (((i_ict_params[2] * *src2) + (1 << 15)) >> 16); + - ((int)(((unsigned)i_ict_params[2] * *src2) + (1 << 15)) >> 16); i2 = *src0 + (2 * *src1) + ((int)((-14942U * *src1) + (1 << 15)) >> 16); *src0++ = i0; *src1++ = i1; diff --git a/libavcodec/jpegls.h b/libavcodec/jpegls.h index c8997c786..6b89b2afa 100644 --- a/libavcodec/jpegls.h +++ b/libavcodec/jpegls.h @@ -32,6 +32,8 @@ #include "avcodec.h" #include "internal.h" +#undef near /* This file uses struct member 'near' which in windows.h is defined as empty. */ + typedef struct JpeglsContext { AVCodecContext *avctx; } JpeglsContext; diff --git a/libavcodec/jpeglsdec.c b/libavcodec/jpeglsdec.c index 64505321a..5308b744d 100644 --- a/libavcodec/jpeglsdec.c +++ b/libavcodec/jpeglsdec.c @@ -233,6 +233,9 @@ static inline void ls_decode_line(JLSState *state, MJpegDecodeContext *s, while (x < w) { int err, pred; + if (get_bits_left(&s->gb) <= 0) + return; + /* compute gradients */ Ra = x ? R(dst, x - stride) : R(last, x); Rb = R(last, x); @@ -443,6 +446,10 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, avpriv_report_missing_feature(s->avctx, "Sample interleaved images"); ret = AVERROR_PATCHWELCOME; goto end; + } else { /* unknown interleaving */ + avpriv_report_missing_feature(s->avctx, "Unknown interleaved images"); + ret = AVERROR_PATCHWELCOME; + goto end; } if (s->xfrm && s->nb_components == 3) { diff --git a/libavcodec/jpegtables.h b/libavcodec/jpegtables.h index 6833b4b16..aa38df403 100644 --- a/libavcodec/jpegtables.h +++ b/libavcodec/jpegtables.h @@ -23,18 +23,18 @@ #include -#include "libavutil/internal.h" +#include "internal.h" -extern av_export const uint8_t avpriv_mjpeg_bits_dc_luminance[]; -extern av_export const uint8_t avpriv_mjpeg_val_dc[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_dc_luminance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_val_dc[]; -extern av_export const uint8_t avpriv_mjpeg_bits_dc_chrominance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_dc_chrominance[]; -extern av_export const uint8_t avpriv_mjpeg_bits_ac_luminance[]; -extern av_export const uint8_t avpriv_mjpeg_val_ac_luminance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_ac_luminance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_val_ac_luminance[]; -extern av_export const uint8_t avpriv_mjpeg_bits_ac_chrominance[]; -extern av_export const uint8_t avpriv_mjpeg_val_ac_chrominance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_ac_chrominance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_val_ac_chrominance[]; void ff_mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code, const uint8_t *bits_table, diff --git a/libavcodec/kgv1dec.c b/libavcodec/kgv1dec.c index 5359411c7..a6bd9400a 100644 --- a/libavcodec/kgv1dec.c +++ b/libavcodec/kgv1dec.c @@ -62,6 +62,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, h = (buf[1] + 1) * 8; buf += 2; + if (avpkt->size < 2 + w*h / 513) + return AVERROR_INVALIDDATA; + if (w != avctx->width || h != avctx->height) { av_freep(&c->frame_buffer); av_freep(&c->last_frame_buffer); diff --git a/libavcodec/libavcodec.v b/libavcodec/libavcodec.v index 304c2ef42..f1d5e5bc7 100644 --- a/libavcodec/libavcodec.v +++ b/libavcodec/libavcodec.v @@ -1,9 +1,6 @@ LIBAVCODEC_MAJOR { global: av*; - #deprecated, remove after next bump - audio_resample; - audio_resample_close; local: *; }; diff --git a/libavcodec/libcelt_dec.c b/libavcodec/libcelt_dec.c index 878e4cc67..75b438b28 100644 --- a/libavcodec/libcelt_dec.c +++ b/libavcodec/libcelt_dec.c @@ -137,4 +137,5 @@ AVCodec ff_libcelt_decoder = { .close = libcelt_dec_close, .decode = libcelt_dec_decode, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libcelt", }; diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c index 2857b9453..677b11088 100644 --- a/libavcodec/libfdk-aacdec.c +++ b/libavcodec/libfdk-aacdec.c @@ -79,7 +79,10 @@ static const AVOption fdk_aac_dec_options[] = { }; static const AVClass fdk_aac_dec_class = { - "libfdk-aac decoder", av_default_item_name, fdk_aac_dec_options, LIBAVUTIL_VERSION_INT + .class_name = "libfdk-aac decoder", + .item_name = av_default_item_name, + .option = fdk_aac_dec_options, + .version = LIBAVUTIL_VERSION_INT, }; static int get_stream_info(AVCodecContext *avctx) @@ -382,4 +385,5 @@ AVCodec ff_libfdk_aac_decoder = { .priv_class = &fdk_aac_dec_class, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libfdk", }; diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c index 0e2051b46..d47137b22 100644 --- a/libavcodec/libfdk-aacenc.c +++ b/libavcodec/libfdk-aacenc.c @@ -54,7 +54,10 @@ static const AVOption aac_enc_options[] = { }; static const AVClass aac_enc_class = { - "libfdk_aac", av_default_item_name, aac_enc_options, LIBAVUTIL_VERSION_INT + .class_name = "libfdk_aac", + .item_name = av_default_item_name, + .option = aac_enc_options, + .version = LIBAVUTIL_VERSION_INT, }; static const char *aac_get_error(AACENC_ERROR err) @@ -425,4 +428,5 @@ AVCodec ff_libfdk_aac_encoder = { .profiles = profiles, .supported_samplerates = aac_sample_rates, .channel_layouts = aac_channel_layout, + .wrapper_name = "libfdk", }; diff --git a/libavcodec/libgsmdec.c b/libavcodec/libgsmdec.c index a503215f6..89e1de0fe 100644 --- a/libavcodec/libgsmdec.c +++ b/libavcodec/libgsmdec.c @@ -135,6 +135,7 @@ AVCodec ff_libgsm_decoder = { .decode = libgsm_decode_frame, .flush = libgsm_flush, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libgsm", }; #endif #if CONFIG_LIBGSM_MS_DECODER @@ -149,5 +150,6 @@ AVCodec ff_libgsm_ms_decoder = { .decode = libgsm_decode_frame, .flush = libgsm_flush, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libgsm", }; #endif diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c index e25db9518..c9e7ba056 100644 --- a/libavcodec/libgsmenc.c +++ b/libavcodec/libgsmenc.c @@ -126,6 +126,7 @@ AVCodec ff_libgsm_encoder = { .close = libgsm_encode_close, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libgsm", }; #endif #if CONFIG_LIBGSM_MS_ENCODER @@ -139,5 +140,6 @@ AVCodec ff_libgsm_ms_encoder = { .close = libgsm_encode_close, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libgsm", }; #endif diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c index c4c054fa5..9a56cc878 100644 --- a/libavcodec/libilbc.c +++ b/libavcodec/libilbc.c @@ -193,4 +193,5 @@ AVCodec ff_libilbc_encoder = { AV_SAMPLE_FMT_NONE }, .defaults = ilbc_encode_defaults, .priv_class = &ilbc_enc_class, + .wrapper_name = "libbilbc", }; diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c index f35b0df61..41a1bbb45 100644 --- a/libavcodec/libkvazaar.c +++ b/libavcodec/libkvazaar.c @@ -231,7 +231,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, kvz_data_chunk *chunk = NULL; uint64_t written = 0; - retval = ff_alloc_packet(avpkt, len_out); + retval = ff_alloc_packet2(avctx, avpkt, len_out, len_out); if (retval < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n"); goto done; @@ -305,4 +305,6 @@ AVCodec ff_libkvazaar_encoder = { .close = libkvazaar_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + + .wrapper_name = "libkvazaar", }; diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c index 5e26743f2..ecdd2e334 100644 --- a/libavcodec/libmp3lame.c +++ b/libavcodec/libmp3lame.c @@ -349,4 +349,5 @@ AVCodec ff_libmp3lame_encoder = { 0 }, .priv_class = &libmp3lame_class, .defaults = libmp3lame_defaults, + .wrapper_name = "libmp3lame", }; diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c index 8545ffe10..516f62572 100644 --- a/libavcodec/libopencore-amr.c +++ b/libavcodec/libopencore-amr.c @@ -183,7 +183,10 @@ static const AVOption options[] = { }; static const AVClass amrnb_class = { - "libopencore_amrnb", av_default_item_name, options, LIBAVUTIL_VERSION_INT + .class_name = "libopencore_amrnb", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; static av_cold int amr_nb_encode_init(AVCodecContext *avctx) @@ -375,6 +378,7 @@ AVCodec ff_libopencore_amrwb_decoder = { .close = amr_wb_decode_close, .decode = amr_wb_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libopencore_amrwb", }; #endif /* CONFIG_LIBOPENCORE_AMRWB_DECODER */ diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index d12e71511..b7ed85d17 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -147,4 +147,5 @@ AVCodec ff_libopenh264_decoder = { .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .bsfs = "h264_mp4toannexb", + .wrapper_name = "libopenh264", }; diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index 9c22bf4f3..fdadb101f 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -75,7 +75,10 @@ static const AVOption options[] = { }; static const AVClass class = { - "libopenh264enc", av_default_item_name, options, LIBAVUTIL_VERSION_INT + .class_name = "libvo_amrwbenc", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; static av_cold int svc_encode_close(AVCodecContext *avctx) @@ -298,4 +301,5 @@ AVCodec ff_libopenh264_encoder = { .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, .priv_class = &class, + .wrapper_name = "libopenh264", }; diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c index 67d47bd6a..5e66cd99c 100644 --- a/libavcodec/libopenjpegdec.c +++ b/libavcodec/libopenjpegdec.c @@ -34,27 +34,7 @@ #include "internal.h" #include "thread.h" -#if HAVE_OPENJPEG_2_3_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_2_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_1_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_1_5_OPENJPEG_H -# include -#else -# include -#endif - -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H || HAVE_OPENJPEG_2_0_OPENJPEG_H -# define OPENJPEG_MAJOR_VERSION 2 -# define OPJ(x) OPJ_##x -#else -# define OPENJPEG_MAJOR_VERSION 1 -# define OPJ(x) x -#endif +#include #define JP2_SIG_TYPE 0x6A502020 #define JP2_SIG_VALUE 0x0D0A870A @@ -97,9 +77,6 @@ static const enum AVPixelFormat libopenjpeg_all_pix_fmts[] = { typedef struct LibOpenJPEGContext { AVClass *class; opj_dparameters_t dec_params; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_event_mgr_t event_mgr; -#endif // OPENJPEG_MAJOR_VERSION == 1 int lowqual; } LibOpenJPEGContext; @@ -118,7 +95,6 @@ static void info_callback(const char *msg, void *data) av_log(data, AV_LOG_DEBUG, "%s", msg); } -#if OPENJPEG_MAJOR_VERSION == 2 typedef struct BufferReader { int pos; int size; @@ -176,7 +152,6 @@ static OPJ_BOOL stream_seek(OPJ_OFF_T nb_bytes, void *user_data) reader->pos = (int)nb_bytes; return OPJ_TRUE; } -#endif // OPENJPEG_MAJOR_VERSION == 2 static inline int libopenjpeg_matches_pix_fmt(const opj_image_t *image, enum AVPixelFormat pix_fmt) { @@ -221,15 +196,15 @@ static inline enum AVPixelFormat libopenjpeg_guess_pix_fmt(const opj_image_t *im int possible_fmts_nb = 0; switch (image->color_space) { - case OPJ(CLRSPC_SRGB): + case OPJ_CLRSPC_SRGB: possible_fmts = libopenjpeg_rgb_pix_fmts; possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_rgb_pix_fmts); break; - case OPJ(CLRSPC_GRAY): + case OPJ_CLRSPC_GRAY: possible_fmts = libopenjpeg_gray_pix_fmts; possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_gray_pix_fmts); break; - case OPJ(CLRSPC_SYCC): + case OPJ_CLRSPC_SYCC: possible_fmts = libopenjpeg_yuv_pix_fmts; possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_yuv_pix_fmts); break; @@ -356,14 +331,9 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, int ispacked = 0; int i; opj_image_t *image = NULL; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_dinfo_t *dec = NULL; - opj_cio_t *stream = NULL; -#else // OPENJPEG_MAJOR_VERSION == 2 BufferReader reader = {0, avpkt->size, avpkt->data}; opj_codec_t *dec = NULL; opj_stream_t *stream = NULL; -#endif // OPENJPEG_MAJOR_VERSION == 1 *got_frame = 0; @@ -371,13 +341,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, if ((AV_RB32(buf) == 12) && (AV_RB32(buf + 4) == JP2_SIG_TYPE) && (AV_RB32(buf + 8) == JP2_SIG_VALUE)) { - dec = opj_create_decompress(OPJ(CODEC_JP2)); + dec = opj_create_decompress(OPJ_CODEC_JP2); } else { /* If the AVPacket contains a jp2c box, then skip to * the starting byte of the codestream. */ if (AV_RB32(buf + 4) == AV_RB32("jp2c")) buf += 8; - dec = opj_create_decompress(OPJ(CODEC_J2K)); + dec = opj_create_decompress(OPJ_CODEC_J2K); } if (!dec) { @@ -386,15 +356,6 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - memset(&ctx->event_mgr, 0, sizeof(ctx->event_mgr)); - ctx->event_mgr.info_handler = info_callback; - ctx->event_mgr.error_handler = error_callback; - ctx->event_mgr.warning_handler = warning_callback; - opj_set_event_mgr((opj_common_ptr) dec, &ctx->event_mgr, avctx); - ctx->dec_params.cp_limit_decoding = LIMIT_TO_MAIN_HEADER; - ctx->dec_params.cp_layer = ctx->lowqual; -#else // OPENJPEG_MAJOR_VERSION == 2 if (!opj_set_error_handler(dec, error_callback, avctx) || !opj_set_warning_handler(dec, warning_callback, avctx) || !opj_set_info_handler(dec, info_callback, avctx)) { @@ -405,16 +366,11 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, ctx->dec_params.cp_layer = ctx->lowqual; ctx->dec_params.cp_reduce = avctx->lowres; -#endif // OPENJPEG_MAJOR_VERSION == 1 // Tie decoder with decoding parameters opj_setup_decoder(dec, &ctx->dec_params); -#if OPENJPEG_MAJOR_VERSION == 1 - stream = opj_cio_open((opj_common_ptr) dec, buf, buf_size); -#else // OPENJPEG_MAJOR_VERSION == 2 stream = opj_stream_default_create(OPJ_STREAM_READ); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (!stream) { av_log(avctx, AV_LOG_ERROR, @@ -423,27 +379,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - // Decode the header only. - image = opj_decode_with_info(dec, stream, NULL); - opj_cio_close(stream); - stream = NULL; - ret = !image; -#else // OPENJPEG_MAJOR_VERSION == 2 opj_stream_set_read_function(stream, stream_read); opj_stream_set_skip_function(stream, stream_skip); opj_stream_set_seek_function(stream, stream_seek); -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H opj_stream_set_user_data(stream, &reader, NULL); -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H - opj_stream_set_user_data(stream, &reader); -#else -#error Missing call to opj_stream_set_user_data -#endif opj_stream_set_user_data_length(stream, avpkt->size); // Decode the header only. ret = !opj_read_header(stream, dec, &image); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (ret) { av_log(avctx, AV_LOG_ERROR, "Error decoding codestream header.\n"); @@ -477,25 +419,7 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) goto done; -#if OPENJPEG_MAJOR_VERSION == 1 - ctx->dec_params.cp_limit_decoding = NO_LIMITATION; - ctx->dec_params.cp_reduce = avctx->lowres; - // Tie decoder with decoding parameters. - opj_setup_decoder(dec, &ctx->dec_params); - stream = opj_cio_open((opj_common_ptr) dec, buf, buf_size); - if (!stream) { - av_log(avctx, AV_LOG_ERROR, - "Codestream could not be opened for reading.\n"); - ret = AVERROR_EXTERNAL; - goto done; - } - opj_image_destroy(image); - // Decode the codestream - image = opj_decode_with_info(dec, stream, NULL); - ret = !image; -#else // OPENJPEG_MAJOR_VERSION == 2 ret = !opj_decode(dec, stream, image); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (ret) { av_log(avctx, AV_LOG_ERROR, "Error decoding codestream.\n"); @@ -556,25 +480,11 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, done: opj_image_destroy(image); -#if OPENJPEG_MAJOR_VERSION == 2 opj_stream_destroy(stream); opj_destroy_codec(dec); -#else - opj_cio_close(stream); - opj_destroy_decompress(dec); -#endif return ret; } -static av_cold void libopenjpeg_static_init(AVCodec *codec) -{ - const char *version = opj_version(); - int major, minor; - - if (sscanf(version, "%d.%d", &major, &minor) == 2 && 1000*major + minor <= 1003) - codec->capabilities |= AV_CODEC_CAP_EXPERIMENTAL; -} - #define OFFSET(x) offsetof(LibOpenJPEGContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM @@ -602,5 +512,5 @@ AVCodec ff_libopenjpeg_decoder = { .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, .max_lowres = 31, .priv_class = &openjpeg_class, - .init_static_data = libopenjpeg_static_init, + .wrapper_name = "libopenjpeg", }; diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 92b4433b0..7c7d0aa6b 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -31,38 +31,11 @@ #include "libavutil/opt.h" #include "avcodec.h" #include "internal.h" - -#if HAVE_OPENJPEG_2_3_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_2_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_1_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_1_5_OPENJPEG_H -# include -#else -# include -#endif - -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H || HAVE_OPENJPEG_2_0_OPENJPEG_H -# define OPENJPEG_MAJOR_VERSION 2 -# define OPJ(x) OPJ_##x -#else -# define OPENJPEG_MAJOR_VERSION 1 -# define OPJ(x) x -#endif +#include typedef struct LibOpenJPEGContext { AVClass *avclass; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_image_t *image; -#endif // OPENJPEG_MAJOR_VERSION == 1 opj_cparameters_t enc_params; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_event_mgr_t event_mgr; -#endif // OPENJPEG_MAJOR_VERSION == 1 int format; int profile; int prog_order; @@ -88,7 +61,6 @@ static void info_callback(const char *msg, void *data) av_log(data, AV_LOG_DEBUG, "%s\n", msg); } -#if OPENJPEG_MAJOR_VERSION == 2 typedef struct PacketWriter { int pos; AVPacket *packet; @@ -158,7 +130,6 @@ static OPJ_BOOL stream_seek(OPJ_OFF_T nb_bytes, void *user_data) writer->pos = (int)nb_bytes; return OPJ_TRUE; } -#endif // OPENJPEG_MAJOR_VERSION == 2 static void cinema_parameters(opj_cparameters_t *p) { @@ -182,7 +153,7 @@ static void cinema_parameters(opj_cparameters_t *p) p->csty |= 0x01; /* The progression order shall be CPRL */ - p->prog_order = OPJ(CPRL); + p->prog_order = OPJ_CPRL; /* No ROI */ p->roi_compno = -1; @@ -206,7 +177,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p int sub_dx[4]; int sub_dy[4]; int numcomps; - OPJ_COLOR_SPACE color_space = OPJ(CLRSPC_UNKNOWN); + OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_UNKNOWN; sub_dx[0] = sub_dx[3] = 1; sub_dy[0] = sub_dy[3] = 1; @@ -220,7 +191,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p case AV_PIX_FMT_YA8: case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YA16: - color_space = OPJ(CLRSPC_GRAY); + color_space = OPJ_CLRSPC_GRAY; break; case AV_PIX_FMT_RGB24: case AV_PIX_FMT_RGBA: @@ -233,7 +204,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p case AV_PIX_FMT_GBRP14: case AV_PIX_FMT_GBRP16: case AV_PIX_FMT_XYZ12: - color_space = OPJ(CLRSPC_SRGB); + color_space = OPJ_CLRSPC_SRGB; break; case AV_PIX_FMT_YUV410P: case AV_PIX_FMT_YUV411P: @@ -268,7 +239,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p case AV_PIX_FMT_YUVA420P16: case AV_PIX_FMT_YUVA422P16: case AV_PIX_FMT_YUVA444P16: - color_space = OPJ(CLRSPC_SYCC); + color_space = OPJ_CLRSPC_SYCC; break; default: av_log(avctx, AV_LOG_ERROR, @@ -309,7 +280,6 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx) opj_set_default_encoder_parameters(&ctx->enc_params); -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H switch (ctx->cinema_mode) { case OPJ_CINEMA2K_24: ctx->enc_params.rsiz = OPJ_PROFILE_CINEMA_2K; @@ -348,12 +318,8 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx) if (err) { av_log(avctx, AV_LOG_ERROR, "Invalid parameter pairing: cinema_mode and profile conflict.\n"); - goto fail; + return err; } -#else - ctx->enc_params.cp_rsiz = ctx->profile; - ctx->enc_params.cp_cinema = ctx->cinema_mode; -#endif if (!ctx->numresolution) { ctx->numresolution = 6; @@ -373,23 +339,7 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx) cinema_parameters(&ctx->enc_params); } -#if OPENJPEG_MAJOR_VERSION == 1 - ctx->image = mj2_create_image(avctx, &ctx->enc_params); - if (!ctx->image) { - av_log(avctx, AV_LOG_ERROR, "Error creating the mj2 image\n"); - err = AVERROR(EINVAL); - goto fail; - } -#endif // OPENJPEG_MAJOR_VERSION == 1 - return 0; - -fail: -#if OPENJPEG_MAJOR_VERSION == 1 - opj_image_destroy(ctx->image); - ctx->image = NULL; -#endif // OPENJPEG_MAJOR_VERSION == 1 - return err; } static int libopenjpeg_copy_packed8(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image) @@ -602,12 +552,6 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, int ret; AVFrame *gbrframe; int cpyresult = 0; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_image_t *image = ctx->image; - opj_cinfo_t *compress = NULL; - opj_cio_t *stream = NULL; - int len; -#else // OPENJPEG_MAJOR_VERSION == 2 PacketWriter writer = { 0 }; opj_codec_t *compress = NULL; opj_stream_t *stream = NULL; @@ -617,7 +561,6 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ret = AVERROR(EINVAL); goto done; } -#endif // OPENJPEG_MAJOR_VERSION == 1 switch (avctx->pix_fmt) { case AV_PIX_FMT_RGB24: @@ -712,11 +655,9 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, goto done; } -#if OPENJPEG_MAJOR_VERSION == 2 if ((ret = ff_alloc_packet2(avctx, pkt, 1024, 0)) < 0) { goto done; } -#endif // OPENJPEG_MAJOR_VERSION == 2 compress = opj_create_compress(ctx->format); if (!compress) { @@ -725,10 +666,6 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - opj_setup_encoder(compress, &ctx->enc_params, image); - stream = opj_cio_open((opj_common_ptr) compress, NULL, 0); -#else // OPENJPEG_MAJOR_VERSION == 2 if (!opj_set_error_handler(compress, error_callback, avctx) || !opj_set_warning_handler(compress, warning_callback, avctx) || !opj_set_info_handler(compress, info_callback, avctx)) { @@ -743,43 +680,18 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, goto done; } stream = opj_stream_default_create(OPJ_STREAM_WRITE); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (!stream) { av_log(avctx, AV_LOG_ERROR, "Error creating the cio stream\n"); ret = AVERROR(ENOMEM); goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - memset(&ctx->event_mgr, 0, sizeof(ctx->event_mgr)); - ctx->event_mgr.info_handler = info_callback; - ctx->event_mgr.error_handler = error_callback; - ctx->event_mgr.warning_handler = warning_callback; - opj_set_event_mgr((opj_common_ptr) compress, &ctx->event_mgr, avctx); - if (!opj_encode(compress, stream, image, NULL)) { - av_log(avctx, AV_LOG_ERROR, "Error during the opj encode\n"); - ret = AVERROR_EXTERNAL; - goto done; - } - len = cio_tell(stream); - if ((ret = ff_alloc_packet2(avctx, pkt, len, 0)) < 0) { - goto done; - } - - memcpy(pkt->data, stream->buffer, len); -#else // OPENJPEG_MAJOR_VERSION == 2 writer.packet = pkt; opj_stream_set_write_function(stream, stream_write); opj_stream_set_skip_function(stream, stream_skip); opj_stream_set_seek_function(stream, stream_seek); -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H opj_stream_set_user_data(stream, &writer, NULL); -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H - opj_stream_set_user_data(stream, &writer); -#else -#error Missing call to opj_stream_set_user_data -#endif if (!opj_start_compress(compress, image, stream) || !opj_encode(compress, stream) || @@ -790,56 +702,39 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } av_shrink_packet(pkt, writer.pos); -#endif // OPENJPEG_MAJOR_VERSION == 1 pkt->flags |= AV_PKT_FLAG_KEY; *got_packet = 1; ret = 0; done: -#if OPENJPEG_MAJOR_VERSION == 2 opj_stream_destroy(stream); opj_destroy_codec(compress); opj_image_destroy(image); -#else - opj_cio_close(stream); - opj_destroy_compress(compress); -#endif return ret; } -static av_cold int libopenjpeg_encode_close(AVCodecContext *avctx) -{ -#if OPENJPEG_MAJOR_VERSION == 1 - LibOpenJPEGContext *ctx = avctx->priv_data; - - opj_image_destroy(ctx->image); - ctx->image = NULL; -#endif // OPENJPEG_MAJOR_VERSION == 1 - return 0; -} - #define OFFSET(x) offsetof(LibOpenJPEGContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "format", "Codec Format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = OPJ(CODEC_JP2) }, OPJ(CODEC_J2K), OPJ(CODEC_JP2), VE, "format" }, - { "j2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CODEC_J2K) }, 0, 0, VE, "format" }, - { "jp2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CODEC_JP2) }, 0, 0, VE, "format" }, - { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = OPJ(STD_RSIZ) }, OPJ(STD_RSIZ), OPJ(CINEMA4K), VE, "profile" }, - { "jpeg2000", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(STD_RSIZ) }, 0, 0, VE, "profile" }, - { "cinema2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA2K) }, 0, 0, VE, "profile" }, - { "cinema4k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA4K) }, 0, 0, VE, "profile" }, - { "cinema_mode", "Digital Cinema", OFFSET(cinema_mode), AV_OPT_TYPE_INT, { .i64 = OPJ(OFF) }, OPJ(OFF), OPJ(CINEMA4K_24), VE, "cinema_mode" }, - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(OFF) }, 0, 0, VE, "cinema_mode" }, - { "2k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA2K_24) }, 0, 0, VE, "cinema_mode" }, - { "2k_48", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA2K_48) }, 0, 0, VE, "cinema_mode" }, - { "4k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA4K_24) }, 0, 0, VE, "cinema_mode" }, - { "prog_order", "Progression Order", OFFSET(prog_order), AV_OPT_TYPE_INT, { .i64 = OPJ(LRCP) }, OPJ(LRCP), OPJ(CPRL), VE, "prog_order" }, - { "lrcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(LRCP) }, 0, 0, VE, "prog_order" }, - { "rlcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(RLCP) }, 0, 0, VE, "prog_order" }, - { "rpcl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(RPCL) }, 0, 0, VE, "prog_order" }, - { "pcrl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(PCRL) }, 0, 0, VE, "prog_order" }, - { "cprl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CPRL) }, 0, 0, VE, "prog_order" }, + { "format", "Codec Format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = OPJ_CODEC_JP2 }, OPJ_CODEC_J2K, OPJ_CODEC_JP2, VE, "format" }, + { "j2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CODEC_J2K }, 0, 0, VE, "format" }, + { "jp2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CODEC_JP2 }, 0, 0, VE, "format" }, + { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = OPJ_STD_RSIZ }, OPJ_STD_RSIZ, OPJ_CINEMA4K, VE, "profile" }, + { "jpeg2000", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_STD_RSIZ }, 0, 0, VE, "profile" }, + { "cinema2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA2K }, 0, 0, VE, "profile" }, + { "cinema4k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA4K }, 0, 0, VE, "profile" }, + { "cinema_mode", "Digital Cinema", OFFSET(cinema_mode), AV_OPT_TYPE_INT, { .i64 = OPJ_OFF }, OPJ_OFF, OPJ_CINEMA4K_24, VE, "cinema_mode" }, + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_OFF }, 0, 0, VE, "cinema_mode" }, + { "2k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA2K_24 }, 0, 0, VE, "cinema_mode" }, + { "2k_48", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA2K_48 }, 0, 0, VE, "cinema_mode" }, + { "4k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA4K_24 }, 0, 0, VE, "cinema_mode" }, + { "prog_order", "Progression Order", OFFSET(prog_order), AV_OPT_TYPE_INT, { .i64 = OPJ_LRCP }, OPJ_LRCP, OPJ_CPRL, VE, "prog_order" }, + { "lrcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_LRCP }, 0, 0, VE, "prog_order" }, + { "rlcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_RLCP }, 0, 0, VE, "prog_order" }, + { "rpcl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_RPCL }, 0, 0, VE, "prog_order" }, + { "pcrl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_PCRL }, 0, 0, VE, "prog_order" }, + { "cprl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CPRL }, 0, 0, VE, "prog_order" }, { "numresolution", NULL, OFFSET(numresolution), AV_OPT_TYPE_INT, { .i64 = 6 }, 0, 33, VE }, { "irreversible", NULL, OFFSET(irreversible), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "disto_alloc", NULL, OFFSET(disto_alloc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, @@ -862,7 +757,6 @@ AVCodec ff_libopenjpeg_encoder = { .priv_data_size = sizeof(LibOpenJPEGContext), .init = libopenjpeg_encode_init, .encode2 = libopenjpeg_encode_frame, - .close = libopenjpeg_encode_close, .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, @@ -884,4 +778,5 @@ AVCodec ff_libopenjpeg_encoder = { AV_PIX_FMT_NONE }, .priv_class = &openjpeg_class, + .wrapper_name = "libopenjpeg", }; diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index e6ca61a78..4f7f4755c 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -24,6 +24,7 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/ffmath.h" #include "avcodec.h" #include "internal.h" @@ -57,8 +58,6 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) 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); @@ -82,14 +81,35 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) 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; + if (channel_map == 1) { + avc->channel_layout = avc->channels > 8 ? 0 : + ff_vorbis_channel_layouts[avc->channels - 1]; + 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; + /* 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; + } + } else if (channel_map == 2) { + int ambisonic_order = ff_sqrt(avc->channels) - 1; + if (avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) && + avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) + 2) { + av_log(avc, AV_LOG_ERROR, + "Channel mapping 2 is only specified for channel counts" + " which can be written as (n + 1)^2 or (n + 2)^2 + 2" + " for nonnegative integer n\n"); + return AVERROR_INVALIDDATA; + } + if (avc->channels > 227) { + av_log(avc, AV_LOG_ERROR, "Too many channels\n"); + return AVERROR_INVALIDDATA; + } + avc->channel_layout = 0; + } else { + avc->channel_layout = 0; } opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels, @@ -203,4 +223,5 @@ AVCodec ff_libopus_decoder = { .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libopus", }; diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index 3d88c296d..b449497d1 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -566,4 +566,5 @@ AVCodec ff_libopus_encoder = { .supported_samplerates = libopus_sample_rates, .priv_class = &libopus_class, .defaults = libopus_defaults, + .wrapper_name = "libopus", }; diff --git a/libavcodec/librsvgdec.c b/libavcodec/librsvgdec.c index 77c771003..e57070f8e 100644 --- a/libavcodec/librsvgdec.c +++ b/libavcodec/librsvgdec.c @@ -124,4 +124,5 @@ AVCodec ff_librsvg_decoder = { .decode = librsvg_decode_frame, .priv_data_size = sizeof(LibRSVGContext), .capabilities = AV_CODEC_CAP_LOSSLESS | AV_CODEC_CAP_DR1, + .wrapper_name = "librsvg", }; diff --git a/libavcodec/libshine.c b/libavcodec/libshine.c index f4cf5981b..7056fcd2e 100644 --- a/libavcodec/libshine.c +++ b/libavcodec/libshine.c @@ -146,4 +146,5 @@ AVCodec ff_libshine_encoder = { .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, 0 }, + .wrapper_name = "libshine", }; diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c index 044883af7..d67c68c7f 100644 --- a/libavcodec/libspeexdec.c +++ b/libavcodec/libspeexdec.c @@ -200,4 +200,5 @@ AVCodec ff_libspeex_decoder = { .decode = libspeex_decode_frame, .flush = libspeex_decode_flush, .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, + .wrapper_name = "libspeex", }; diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c index a2b07a41c..6a37dbc76 100644 --- a/libavcodec/libspeexenc.c +++ b/libavcodec/libspeexenc.c @@ -159,9 +159,9 @@ static av_cold int encode_init(AVCodecContext *avctx) /* sample rate and encoding mode */ switch (avctx->sample_rate) { - case 8000: mode = &speex_nb_mode; break; - case 16000: mode = &speex_wb_mode; break; - case 32000: mode = &speex_uwb_mode; break; + case 8000: mode = speex_lib_get_mode(SPEEX_MODEID_NB); break; + case 16000: mode = speex_lib_get_mode(SPEEX_MODEID_WB); break; + case 32000: mode = speex_lib_get_mode(SPEEX_MODEID_UWB); break; default: av_log(avctx, AV_LOG_ERROR, "Sample rate of %d Hz is not supported. " "Resample to 8, 16, or 32 kHz.\n", avctx->sample_rate); @@ -365,4 +365,5 @@ AVCodec ff_libspeex_encoder = { .supported_samplerates = (const int[]){ 8000, 16000, 32000, 0 }, .priv_class = &speex_class, .defaults = defaults, + .wrapper_name = "libspeex", }; diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index fae55e8f2..16966ed43 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -208,7 +208,9 @@ static av_cold int encode_init(AVCodecContext* avc_context) av_log(avc_context, AV_LOG_ERROR, "Unsupported pix_fmt\n"); return AVERROR(EINVAL); } - avcodec_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift); + ret = av_pix_fmt_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift); + if (ret) + return ret; if (avc_context->flags & AV_CODEC_FLAG_QSCALE) { /* Clip global_quality in QP units to the [0 - 10] range @@ -383,4 +385,5 @@ AVCodec ff_libtheora_encoder = { .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + .wrapper_name = "libtheora", }; diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c index 12d71e7ac..030f88868 100644 --- a/libavcodec/libtwolame.c +++ b/libavcodec/libtwolame.c @@ -226,4 +226,5 @@ AVCodec ff_libtwolame_encoder = { AV_CH_LAYOUT_STEREO, 0 }, .supported_samplerates = twolame_samplerates, + .wrapper_name = "libtwolame", }; diff --git a/libavcodec/libvo-amrwbenc.c b/libavcodec/libvo-amrwbenc.c index 2a1565057..77d0ccef1 100644 --- a/libavcodec/libvo-amrwbenc.c +++ b/libavcodec/libvo-amrwbenc.c @@ -46,7 +46,10 @@ static const AVOption options[] = { }; static const AVClass amrwb_class = { - "libvo_amrwbenc", av_default_item_name, options, LIBAVUTIL_VERSION_INT + .class_name = "libvo_amrwbenc", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; static int get_wb_bitrate_mode(int bitrate, void *log_ctx) @@ -149,4 +152,5 @@ AVCodec ff_libvo_amrwbenc_encoder = { .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, .priv_class = &amrwb_class, + .wrapper_name = "libvo_amrwbenc", }; diff --git a/libavcodec/libvorbisenc.c b/libavcodec/libvorbisenc.c index 3ca5b55e8..f78f872fe 100644 --- a/libavcodec/libvorbisenc.c +++ b/libavcodec/libvorbisenc.c @@ -377,4 +377,5 @@ AVCodec ff_libvorbis_encoder = { AV_SAMPLE_FMT_NONE }, .priv_class = &vorbis_class, .defaults = defaults, + .wrapper_name = "libvorbis", }; diff --git a/libavcodec/libvpx.c b/libavcodec/libvpx.c index 1eca97a08..cc055a003 100644 --- a/libavcodec/libvpx.c +++ b/libavcodec/libvpx.c @@ -40,9 +40,7 @@ static const enum AVPixelFormat vp9_pix_fmts_highcol[] = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, -#if VPX_IMAGE_ABI_VERSION >= 3 AV_PIX_FMT_GBRP, -#endif AV_PIX_FMT_NONE }; @@ -60,88 +58,23 @@ static const enum AVPixelFormat vp9_pix_fmts_highbd[] = { AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV444P12, -#if VPX_IMAGE_ABI_VERSION >= 3 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, -#endif AV_PIX_FMT_NONE }; #endif av_cold void ff_vp9_init_static(AVCodec *codec) { - if ( vpx_codec_version_major() < 1 - || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3)) - codec->capabilities |= AV_CODEC_CAP_EXPERIMENTAL; codec->pix_fmts = vp9_pix_fmts_def; #if CONFIG_LIBVPX_VP9_ENCODER - if ( vpx_codec_version_major() > 1 - || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() >= 4)) { -#ifdef VPX_CODEC_CAP_HIGHBITDEPTH + { vpx_codec_caps_t codec_caps = vpx_codec_get_caps(vpx_codec_vp9_cx()); if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) codec->pix_fmts = vp9_pix_fmts_highbd; else -#endif codec->pix_fmts = vp9_pix_fmts_highcol; } #endif } -#if 0 -enum AVPixelFormat ff_vpx_imgfmt_to_pixfmt(vpx_img_fmt_t img) -{ - switch (img) { - case VPX_IMG_FMT_RGB24: return AV_PIX_FMT_RGB24; - case VPX_IMG_FMT_RGB565: return AV_PIX_FMT_RGB565BE; - case VPX_IMG_FMT_RGB555: return AV_PIX_FMT_RGB555BE; - case VPX_IMG_FMT_UYVY: return AV_PIX_FMT_UYVY422; - case VPX_IMG_FMT_YUY2: return AV_PIX_FMT_YUYV422; - case VPX_IMG_FMT_YVYU: return AV_PIX_FMT_YVYU422; - case VPX_IMG_FMT_BGR24: return AV_PIX_FMT_BGR24; - case VPX_IMG_FMT_ARGB: return AV_PIX_FMT_ARGB; - case VPX_IMG_FMT_ARGB_LE: return AV_PIX_FMT_BGRA; - case VPX_IMG_FMT_RGB565_LE: return AV_PIX_FMT_RGB565LE; - case VPX_IMG_FMT_RGB555_LE: return AV_PIX_FMT_RGB555LE; - case VPX_IMG_FMT_I420: return AV_PIX_FMT_YUV420P; - case VPX_IMG_FMT_I422: return AV_PIX_FMT_YUV422P; - case VPX_IMG_FMT_I444: return AV_PIX_FMT_YUV444P; - case VPX_IMG_FMT_444A: return AV_PIX_FMT_YUVA444P; -#if VPX_IMAGE_ABI_VERSION >= 3 - case VPX_IMG_FMT_I440: return AV_PIX_FMT_YUV440P; - case VPX_IMG_FMT_I42016: return AV_PIX_FMT_YUV420P16BE; - case VPX_IMG_FMT_I42216: return AV_PIX_FMT_YUV422P16BE; - case VPX_IMG_FMT_I44416: return AV_PIX_FMT_YUV444P16BE; -#endif - default: return AV_PIX_FMT_NONE; - } -} - -vpx_img_fmt_t ff_vpx_pixfmt_to_imgfmt(enum AVPixelFormat pix) -{ - switch (pix) { - case AV_PIX_FMT_RGB24: return VPX_IMG_FMT_RGB24; - case AV_PIX_FMT_RGB565BE: return VPX_IMG_FMT_RGB565; - case AV_PIX_FMT_RGB555BE: return VPX_IMG_FMT_RGB555; - case AV_PIX_FMT_UYVY422: return VPX_IMG_FMT_UYVY; - case AV_PIX_FMT_YUYV422: return VPX_IMG_FMT_YUY2; - case AV_PIX_FMT_YVYU422: return VPX_IMG_FMT_YVYU; - case AV_PIX_FMT_BGR24: return VPX_IMG_FMT_BGR24; - case AV_PIX_FMT_ARGB: return VPX_IMG_FMT_ARGB; - case AV_PIX_FMT_BGRA: return VPX_IMG_FMT_ARGB_LE; - case AV_PIX_FMT_RGB565LE: return VPX_IMG_FMT_RGB565_LE; - case AV_PIX_FMT_RGB555LE: return VPX_IMG_FMT_RGB555_LE; - case AV_PIX_FMT_YUV420P: return VPX_IMG_FMT_I420; - case AV_PIX_FMT_YUV422P: return VPX_IMG_FMT_I422; - case AV_PIX_FMT_YUV444P: return VPX_IMG_FMT_I444; - case AV_PIX_FMT_YUVA444P: return VPX_IMG_FMT_444A; -#if VPX_IMAGE_ABI_VERSION >= 3 - case AV_PIX_FMT_YUV440P: return VPX_IMG_FMT_I440; - case AV_PIX_FMT_YUV420P16BE: return VPX_IMG_FMT_I42016; - case AV_PIX_FMT_YUV422P16BE: return VPX_IMG_FMT_I42216; - case AV_PIX_FMT_YUV444P16BE: return VPX_IMG_FMT_I44416; -#endif - default: return VPX_IMG_FMT_NONE; - } -} -#endif diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c index ad0ea3b02..04f27d339 100644 --- a/libavcodec/libvpxdec.c +++ b/libavcodec/libvpxdec.c @@ -70,7 +70,6 @@ static av_cold int vpx_init(AVCodecContext *avctx, static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, int has_alpha_channel) { -#if VPX_IMAGE_ABI_VERSION >= 3 static const enum AVColorSpace colorspaces[8] = { AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M, AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB, @@ -82,7 +81,6 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, avctx->color_range = color_ranges[img->range]; #endif avctx->colorspace = colorspaces[img->cs]; -#endif if (avctx->codec_id == AV_CODEC_ID_VP8 && img->fmt != VPX_IMG_FMT_I420) return AVERROR_INVALIDDATA; switch (img->fmt) { @@ -97,22 +95,15 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, avctx->profile = FF_PROFILE_VP9_1; avctx->pix_fmt = AV_PIX_FMT_YUV422P; return 0; -#if VPX_IMAGE_ABI_VERSION >= 3 case VPX_IMG_FMT_I440: avctx->profile = FF_PROFILE_VP9_1; avctx->pix_fmt = AV_PIX_FMT_YUV440P; return 0; -#endif case VPX_IMG_FMT_I444: avctx->profile = FF_PROFILE_VP9_1; -#if VPX_IMAGE_ABI_VERSION >= 3 avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P; -#else - avctx->pix_fmt = AV_PIX_FMT_YUV444P; -#endif return 0; -#ifdef VPX_IMG_FMT_HIGHBITDEPTH case VPX_IMG_FMT_I42016: avctx->profile = FF_PROFILE_VP9_2; if (img->bit_depth == 10) { @@ -135,7 +126,6 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, } else { return AVERROR_INVALIDDATA; } -#if VPX_IMAGE_ABI_VERSION >= 3 case VPX_IMG_FMT_I44016: avctx->profile = FF_PROFILE_VP9_3; if (img->bit_depth == 10) { @@ -147,29 +137,19 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, } else { return AVERROR_INVALIDDATA; } -#endif case VPX_IMG_FMT_I44416: avctx->profile = FF_PROFILE_VP9_3; if (img->bit_depth == 10) { -#if VPX_IMAGE_ABI_VERSION >= 3 avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10; -#else - avctx->pix_fmt = AV_PIX_FMT_YUV444P10; -#endif return 0; } else if (img->bit_depth == 12) { -#if VPX_IMAGE_ABI_VERSION >= 3 avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12; -#else - avctx->pix_fmt = AV_PIX_FMT_YUV444P12; -#endif return 0; } else { return AVERROR_INVALIDDATA; } -#endif #endif default: return AVERROR_INVALIDDATA; @@ -252,13 +232,8 @@ static int vpx_decode(AVCodecContext *avctx, } if ((ret = set_pix_fmt(avctx, img, ctx->has_alpha_channel)) < 0) { -#ifdef VPX_IMG_FMT_HIGHBITDEPTH av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", img->fmt, img->bit_depth); -#else - av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", - img->fmt, 8); -#endif return ret; } @@ -314,6 +289,7 @@ AVCodec ff_libvpx_vp8_decoder = { .close = vpx_free, .decode = vpx_decode, .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1, + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP8_DECODER */ @@ -335,5 +311,6 @@ AVCodec ff_libvpx_vp9_decoder = { .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1, .init_static_data = ff_vp9_init_static, .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP9_DECODER */ diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 64a745933..d0bd1e997 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -109,6 +109,8 @@ typedef struct VPxEncoderContext { int vpx_cs; float level; int row_mt; + int tune_content; + int corpus_complexity; } VPxContext; /** String mappings for enum vp8e_enc_control_id */ @@ -130,9 +132,7 @@ static const char *const ctlidstr[] = { [VP9E_SET_TILE_ROWS] = "VP9E_SET_TILE_ROWS", [VP9E_SET_FRAME_PARALLEL_DECODING] = "VP9E_SET_FRAME_PARALLEL_DECODING", [VP9E_SET_AQ_MODE] = "VP9E_SET_AQ_MODE", -#if VPX_ENCODER_ABI_VERSION > 8 [VP9E_SET_COLOR_SPACE] = "VP9E_SET_COLOR_SPACE", -#endif #if VPX_ENCODER_ABI_VERSION >= 11 [VP9E_SET_COLOR_RANGE] = "VP9E_SET_COLOR_RANGE", #endif @@ -143,6 +143,9 @@ static const char *const ctlidstr[] = { #ifdef VPX_CTRL_VP9E_SET_ROW_MT [VP9E_SET_ROW_MT] = "VP9E_SET_ROW_MT", #endif +#ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT + [VP9E_SET_TUNE_CONTENT] = "VP9E_SET_TUNE_CONTENT", +#endif #endif }; @@ -166,7 +169,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, av_log(avctx, level, "vpx_codec_enc_cfg\n"); av_log(avctx, level, "generic settings\n" " %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n" -#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH) +#if CONFIG_LIBVPX_VP9_ENCODER " %*s%u\n %*s%u\n" #endif " %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n", @@ -175,7 +178,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "g_profile:", cfg->g_profile, width, "g_w:", cfg->g_w, width, "g_h:", cfg->g_h, -#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH) +#if CONFIG_LIBVPX_VP9_ENCODER width, "g_bit_depth:", cfg->g_bit_depth, width, "g_input_bit_depth:", cfg->g_input_bit_depth, #endif @@ -211,6 +214,10 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "rc_2pass_vbr_bias_pct:", cfg->rc_2pass_vbr_bias_pct, width, "rc_2pass_vbr_minsection_pct:", cfg->rc_2pass_vbr_minsection_pct, width, "rc_2pass_vbr_maxsection_pct:", cfg->rc_2pass_vbr_maxsection_pct); +#if VPX_ENCODER_ABI_VERSION >= 14 + av_log(avctx, level, " %*s%u\n", + width, "rc_2pass_vbr_corpus_complexity:", cfg->rc_2pass_vbr_corpus_complexity); +#endif av_log(avctx, level, "keyframing settings\n" " %*s%d\n %*s%u\n %*s%u\n", width, "kf_mode:", cfg->kf_mode, @@ -320,9 +327,7 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, vpx_img_fmt_t *img_fmt) { VPxContext av_unused *ctx = avctx->priv_data; -#ifdef VPX_IMG_FMT_HIGHBITDEPTH enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8; -#endif switch (avctx->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVA420P: @@ -333,19 +338,16 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I422; return 0; -#if VPX_IMAGE_ABI_VERSION >= 3 case AV_PIX_FMT_YUV440P: enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I440; return 0; case AV_PIX_FMT_GBRP: ctx->vpx_cs = VPX_CS_SRGB; -#endif case AV_PIX_FMT_YUV444P: enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I444; return 0; -#ifdef VPX_IMG_FMT_HIGHBITDEPTH case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV420P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { @@ -368,7 +370,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, return 0; } break; -#if VPX_IMAGE_ABI_VERSION >= 3 case AV_PIX_FMT_YUV440P10: case AV_PIX_FMT_YUV440P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { @@ -383,7 +384,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, case AV_PIX_FMT_GBRP10: case AV_PIX_FMT_GBRP12: ctx->vpx_cs = VPX_CS_SRGB; -#endif case AV_PIX_FMT_YUV444P10: case AV_PIX_FMT_YUV444P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { @@ -396,7 +396,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, return 0; } break; -#endif default: break; } @@ -404,7 +403,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, return AVERROR_INVALIDDATA; } -#if VPX_ENCODER_ABI_VERSION > 8 static void set_colorspace(AVCodecContext *avctx) { enum vpx_color_space vpx_cs; @@ -430,7 +428,6 @@ static void set_colorspace(AVCodecContext *avctx) } codecctl_int(avctx, VP9E_SET_COLOR_SPACE, vpx_cs); } -#endif #if VPX_ENCODER_ABI_VERSION >= 11 static void set_color_range(AVCodecContext *avctx) @@ -573,6 +570,14 @@ FF_ENABLE_DEPRECATION_WARNINGS if (avctx->rc_max_rate) enccfg.rc_2pass_vbr_maxsection_pct = avctx->rc_max_rate * 100LL / avctx->bit_rate; +#if CONFIG_LIBVPX_VP9_ENCODER + if (avctx->codec_id == AV_CODEC_ID_VP9) { +#if VPX_ENCODER_ABI_VERSION >= 14 + if (ctx->corpus_complexity >= 0) + enccfg.rc_2pass_vbr_corpus_complexity = ctx->corpus_complexity; +#endif + } +#endif if (avctx->rc_buffer_size) enccfg.rc_buf_sz = @@ -581,15 +586,6 @@ FF_ENABLE_DEPRECATION_WARNINGS enccfg.rc_buf_initial_sz = avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate; enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->rc_buffer_aggressivity != 1.0) { - av_log(avctx, AV_LOG_WARNING, "The rc_buffer_aggressivity option is " - "deprecated, use the undershoot-pct private option instead.\n"); - enccfg.rc_undershoot_pct = lrint(avctx->rc_buffer_aggressivity * 100); - } - FF_ENABLE_DEPRECATION_WARNINGS -#endif if (ctx->rc_undershoot_pct >= 0) enccfg.rc_undershoot_pct = ctx->rc_undershoot_pct; if (ctx->rc_overshoot_pct >= 0) @@ -688,15 +684,6 @@ FF_ENABLE_DEPRECATION_WARNINGS codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, ctx->noise_sensitivity); codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices)); } -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->mb_threshold) { - av_log(avctx, AV_LOG_WARNING, "The mb_threshold option is deprecated, " - "use the static-thresh private option instead.\n"); - ctx->static_thresh = avctx->mb_threshold; - } - FF_ENABLE_DEPRECATION_WARNINGS -#endif codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0) codecctl_int(avctx, VP8E_SET_CQ_LEVEL, ctx->crf); @@ -715,9 +702,7 @@ FF_ENABLE_DEPRECATION_WARNINGS codecctl_int(avctx, VP9E_SET_FRAME_PARALLEL_DECODING, ctx->frame_parallel); if (ctx->aq_mode >= 0) codecctl_int(avctx, VP9E_SET_AQ_MODE, ctx->aq_mode); -#if VPX_ENCODER_ABI_VERSION > 8 set_colorspace(avctx); -#endif #if VPX_ENCODER_ABI_VERSION >= 11 set_color_range(avctx); #endif @@ -727,6 +712,10 @@ FF_ENABLE_DEPRECATION_WARNINGS #ifdef VPX_CTRL_VP9E_SET_ROW_MT if (ctx->row_mt >= 0) codecctl_int(avctx, VP9E_SET_ROW_MT, ctx->row_mt); +#endif +#ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT + if (ctx->tune_content >= 0) + codecctl_int(avctx, VP9E_SET_TUNE_CONTENT, ctx->tune_content); #endif } #endif @@ -736,7 +725,7 @@ FF_ENABLE_DEPRECATION_WARNINGS //provide dummy value to initialize wrapper, values will be updated each _encode() vpx_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1, (unsigned char*)1); -#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH) +#if CONFIG_LIBVPX_VP9_ENCODER if (avctx->codec_id == AV_CODEC_ID_VP9 && (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH)) ctx->rawimg.bit_depth = enccfg.g_bit_depth; #endif @@ -1077,11 +1066,6 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(VPxContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -#ifndef VPX_ERROR_RESILIENT_DEFAULT -#define VPX_ERROR_RESILIENT_DEFAULT 1 -#define VPX_ERROR_RESILIENT_PARTITIONS 2 -#endif - #define COMMON_OPTIONS \ { "auto-alt-ref", "Enable use of alternate reference " \ "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, \ @@ -1157,6 +1141,21 @@ static const AVOption vp9_options[] = { #endif #ifdef VPX_CTRL_VP9E_SET_ROW_MT {"row-mt", "Row based multi-threading", OFFSET(row_mt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, +#endif +#ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT +#if VPX_ENCODER_ABI_VERSION >= 14 + { "tune-content", "Tune content type", OFFSET(tune_content), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE, "tune_content" }, +#else + { "tune-content", "Tune content type", OFFSET(tune_content), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE, "tune_content" }, +#endif + { "default", "Regular video content", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, VE, "tune_content" }, + { "screen", "Screen capture content", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "tune_content" }, +#if VPX_ENCODER_ABI_VERSION >= 14 + { "film", "Film content; improves grain retention", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "tune_content" }, +#endif +#endif +#if VPX_ENCODER_ABI_VERSION >= 14 + { "corpus-complexity", "corpus vbr complexity midpoint", OFFSET(corpus_complexity), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 10000, VE }, #endif LEGACY_OPTIONS { NULL } @@ -1200,6 +1199,7 @@ AVCodec ff_libvpx_vp8_encoder = { .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE }, .priv_class = &class_vp8, .defaults = defaults, + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP8_ENCODER */ @@ -1230,5 +1230,6 @@ AVCodec ff_libvpx_vp9_encoder = { .priv_class = &class_vp9, .defaults = defaults, .init_static_data = ff_vp9_init_static, + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP9_ENCODER */ diff --git a/libavcodec/libwavpackenc.c b/libavcodec/libwavpackenc.c index 6d5708985..e84b07489 100644 --- a/libavcodec/libwavpackenc.c +++ b/libavcodec/libwavpackenc.c @@ -191,4 +191,5 @@ AVCodec ff_libwavpack_encoder = { .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SMALL_LAST_FRAME, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libwavpack", }; diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c index 0bcf628e5..48f45b632 100644 --- a/libavcodec/libwebpenc.c +++ b/libavcodec/libwebpenc.c @@ -109,4 +109,5 @@ AVCodec ff_libwebp_encoder = { }, .priv_class = &class, .defaults = libwebp_defaults, + .wrapper_name = "libwebp", }; diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c index 91bf64ca8..7f35a0b93 100644 --- a/libavcodec/libwebpenc_animencoder.c +++ b/libavcodec/libwebpenc_animencoder.c @@ -148,4 +148,5 @@ AVCodec ff_libwebp_anim_encoder = { }, .priv_class = &class, .defaults = libwebp_defaults, + .wrapper_name = "libwebp", }; diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index b11ede619..12379ff76 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -279,7 +279,11 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, x264_picture_init( &x4->pic ); x4->pic.img.i_csp = x4->params.i_csp; +#if X264_BUILD >= 153 + if (x4->params.i_bitdepth > 8) +#else if (x264_bit_depth > 8) +#endif x4->pic.img.i_csp |= X264_CSP_HIGH_DEPTH; x4->pic.img.i_plane = avfmt2_num_planes(ctx->pix_fmt); @@ -490,6 +494,9 @@ static av_cold int X264_init(AVCodecContext *avctx) x4->params.p_log_private = avctx; x4->params.i_log_level = X264_LOG_DEBUG; x4->params.i_csp = convert_pix_fmt(avctx->pix_fmt); +#if X264_BUILD >= 153 + x4->params.i_bitdepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth; +#endif PARSE_X264_OPT("weightp", wpredp); @@ -701,24 +708,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if (x4->nal_hrd >= 0) x4->params.i_nal_hrd = x4->nal_hrd; - if (x4->motion_est >= 0) { + if (x4->motion_est >= 0) x4->params.analyse.i_me_method = x4->motion_est; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - } else { - if (avctx->me_method == ME_EPZS) - x4->params.analyse.i_me_method = X264_ME_DIA; - else if (avctx->me_method == ME_HEX) - x4->params.analyse.i_me_method = X264_ME_HEX; - else if (avctx->me_method == ME_UMH) - x4->params.analyse.i_me_method = X264_ME_UMH; - else if (avctx->me_method == ME_FULL) - x4->params.analyse.i_me_method = X264_ME_ESA; - else if (avctx->me_method == ME_TESA) - x4->params.analyse.i_me_method = X264_ME_TESA; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } if (x4->coder >= 0) x4->params.b_cabac = x4->coder; @@ -878,6 +869,24 @@ static const enum AVPixelFormat pix_fmts_10bit[] = { AV_PIX_FMT_NV20, AV_PIX_FMT_NONE }; +static const enum AVPixelFormat pix_fmts_all[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_NV12, + AV_PIX_FMT_NV16, +#ifdef X264_CSP_NV21 + AV_PIX_FMT_NV21, +#endif + AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_NV20, + AV_PIX_FMT_NONE +}; #if CONFIG_LIBX264RGB_ENCODER static const enum AVPixelFormat pix_fmts_8bit_rgb[] = { AV_PIX_FMT_BGR0, @@ -889,12 +898,16 @@ static const enum AVPixelFormat pix_fmts_8bit_rgb[] = { static av_cold void X264_init_static(AVCodec *codec) { +#if X264_BUILD < 153 if (x264_bit_depth == 8) codec->pix_fmts = pix_fmts_8bit; else if (x264_bit_depth == 9) codec->pix_fmts = pix_fmts_9bit; else if (x264_bit_depth == 10) codec->pix_fmts = pix_fmts_10bit; +#else + codec->pix_fmts = pix_fmts_all; +#endif } #define OFFSET(x) offsetof(X264Context, x) @@ -958,6 +971,7 @@ static const AVOption options[] = { { "vbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_VBR}, INT_MIN, INT_MAX, VE, "nal-hrd" }, { "cbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_CBR}, INT_MIN, INT_MAX, VE, "nal-hrd" }, { "avcintra-class","AVC-Intra class 50/100/200", OFFSET(avcintra_class),AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 200 , VE}, + { "me_method", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, X264_ME_TESA, VE, "motion-est"}, { "motion-est", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, X264_ME_TESA, VE, "motion-est"}, { "dia", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = X264_ME_DIA }, INT_MIN, INT_MAX, VE, "motion-est" }, { "hex", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = X264_ME_HEX }, INT_MIN, INT_MAX, VE, "motion-est" }, @@ -1002,9 +1016,6 @@ static const AVCodecDefault x264_defaults[] = { { "nr", "-1" }, #endif { "me_range", "-1" }, -#if FF_API_MOTION_EST - { "me_method", "-1" }, -#endif { "subq", "-1" }, #if FF_API_PRIVATE_OPT { "b_strategy", "-1" }, @@ -1044,6 +1055,7 @@ AVCodec ff_libx264_encoder = { .init_static_data = X264_init_static, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libx264", }; #endif @@ -1068,6 +1080,7 @@ AVCodec ff_libx264rgb_encoder = { .priv_class = &rgbclass, .defaults = x264_defaults, .pix_fmts = pix_fmts_8bit_rgb, + .wrapper_name = "libx264", }; #endif @@ -1094,5 +1107,6 @@ AVCodec ff_libx262_encoder = { .pix_fmts = pix_fmts_8bit, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libx264", }; #endif diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index 784b51c52..3c97800cc 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -45,6 +45,7 @@ typedef struct libx265Context { int forced_idr; char *preset; char *tune; + char *profile; char *x265_opts; } libx265Context; @@ -114,11 +115,11 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) ctx->params->sourceHeight = avctx->height; ctx->params->bEnablePsnr = !!(avctx->flags & AV_CODEC_FLAG_PSNR); - if ((avctx->color_primaries <= AVCOL_PRI_BT2020 && + if ((avctx->color_primaries <= AVCOL_PRI_SMPTE432 && avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) || - (avctx->color_trc <= AVCOL_TRC_BT2020_12 && + (avctx->color_trc <= AVCOL_TRC_ARIB_STD_B67 && avctx->color_trc != AVCOL_TRC_UNSPECIFIED) || - (avctx->colorspace <= AVCOL_SPC_BT2020_CL && + (avctx->colorspace <= AVCOL_SPC_ICTCP && avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) { ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1; @@ -220,6 +221,18 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) } } + if (ctx->profile) { + if (ctx->api->param_apply_profile(ctx->params, ctx->profile) < 0) { + int i; + av_log(avctx, AV_LOG_ERROR, "Invalid or incompatible profile set: %s.\n", ctx->profile); + av_log(avctx, AV_LOG_INFO, "Possible profiles:"); + for (i = 0; x265_profile_names[i]; i++) + av_log(avctx, AV_LOG_INFO, " %s", x265_profile_names[i]); + av_log(avctx, AV_LOG_INFO, "\n"); + return AVERROR(EINVAL); + } + } + ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); @@ -294,7 +307,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, for (i = 0; i < nnal; i++) payload += nal[i].sizeBytes; - ret = ff_alloc_packet(pkt, payload); + ret = ff_alloc_packet2(avctx, pkt, payload, payload); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); return ret; @@ -329,6 +342,13 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif +#if X265_BUILD >= 130 + if (x265pic_out.sliceType == X265_TYPE_B) +#else + if (x265pic_out.frameData.sliceType == 'b') +#endif + pkt->flags |= AV_PKT_FLAG_DISPOSABLE; + *got_packet = 1; return 0; } @@ -392,6 +412,7 @@ static const AVOption options[] = { { "forced-idr", "if forcing keyframes, force them as IDR frames", OFFSET(forced_idr),AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, + { "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { NULL } }; @@ -421,4 +442,5 @@ AVCodec ff_libx265_encoder = { .priv_class = &class, .defaults = x265_defaults, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .wrapper_name = "libx265", }; diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c index f257e5584..801a05dbb 100644 --- a/libavcodec/libxavs.c +++ b/libavcodec/libxavs.c @@ -283,32 +283,6 @@ static av_cold int XAVS_init(AVCodecContext *avctx) if (x4->cplxblur >= 0) x4->params.rc.f_complexity_blur = x4->cplxblur; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - if (x4->motion_est < 0) { - switch (avctx->me_method) { - case ME_EPZS: - x4->params.analyse.i_me_method = XAVS_ME_DIA; - break; - case ME_HEX: - x4->params.analyse.i_me_method = XAVS_ME_HEX; - break; - case ME_UMH: - x4->params.analyse.i_me_method = XAVS_ME_UMH; - break; - case ME_FULL: - x4->params.analyse.i_me_method = XAVS_ME_ESA; - break; - case ME_TESA: - x4->params.analyse.i_me_method = XAVS_ME_TESA; - break; - default: - x4->params.analyse.i_me_method = XAVS_ME_HEX; - } - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - x4->params.i_bframe = avctx->max_b_frames; /* cabac is not included in AVS JiZhun Profile */ x4->params.b_cabac = 0; @@ -465,7 +439,7 @@ static const AVOption options[] = { { "mbtree", "Use macroblock tree ratecontrol.", OFFSET(mbtree), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "mixed-refs", "One reference per partition, as opposed to one reference per macroblock", OFFSET(mixed_refs), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, { "fast-pskip", NULL, OFFSET(fast_pskip), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, - { "motion-est", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, XAVS_ME_TESA, VE, "motion-est"}, + { "motion-est", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = XAVS_ME_DIA }, -1, XAVS_ME_TESA, VE, "motion-est"}, { "dia", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_ME_DIA }, INT_MIN, INT_MAX, VE, "motion-est" }, { "hex", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_ME_HEX }, INT_MIN, INT_MAX, VE, "motion-est" }, { "umh", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_ME_UMH }, INT_MIN, INT_MAX, VE, "motion-est" }, @@ -504,4 +478,5 @@ AVCodec ff_libxavs_encoder = { .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, .priv_class = &xavs_class, .defaults = xavs_defaults, + .wrapper_name = "libxavs", }; diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c index d916f1171..cdaae2094 100644 --- a/libavcodec/libxvid.c +++ b/libavcodec/libxvid.c @@ -418,30 +418,6 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) case 1: x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - break; - default: - switch (avctx->me_method) { - case ME_FULL: /* Quality 6 */ - x->me_flags |= XVID_ME_EXTSEARCH16 | - XVID_ME_EXTSEARCH8; - case ME_EPZS: /* Quality 4 */ - x->me_flags |= XVID_ME_ADVANCEDDIAMOND8 | - XVID_ME_HALFPELREFINE8 | - XVID_ME_CHROMA_PVOP | - XVID_ME_CHROMA_BVOP; - case ME_LOG: /* Quality 2 */ - case ME_PHODS: - case ME_X1: - x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 | - XVID_ME_HALFPELREFINE16; - case ME_ZERO: /* Quality 0 */ - default: - break; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif } /* Decide how we should decide blocks */ @@ -462,11 +438,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } /* Bring in VOL flags from ffmpeg command-line */ -#if FF_API_GMC - if (avctx->flags & CODEC_FLAG_GMC) - x->gmc = 1; -#endif - x->vol_flags = 0; if (x->gmc) { x->vol_flags |= XVID_VOL_GMC; @@ -938,7 +909,7 @@ static const AVOption options[] = { { "frame", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "ssim" }, { "ssim_acc", "SSIM accuracy", OFFSET(ssim_acc), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, VE }, { "gmc", "use GMC", OFFSET(gmc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, - { "me_quality", "Motion estimation quality", OFFSET(me_quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 6, VE }, + { "me_quality", "Motion estimation quality", OFFSET(me_quality), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 6, VE }, { "mpeg_quant", "Use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { NULL }, }; @@ -963,4 +934,5 @@ AVCodec ff_libxvid_encoder = { .priv_class = &xvid_class, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libxvid", }; diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c index 687b6af12..30d059343 100644 --- a/libavcodec/libzvbi-teletextdec.c +++ b/libavcodec/libzvbi-teletextdec.c @@ -573,4 +573,5 @@ AVCodec ff_libzvbi_teletext_decoder = { .capabilities = AV_CODEC_CAP_DELAY, .flush = teletext_flush, .priv_class= &teletext_class, + .wrapper_name = "libzvbi", }; diff --git a/libavcodec/lossless_videodsp.c b/libavcodec/lossless_videodsp.c index b5b96e612..cff94c234 100644 --- a/libavcodec/lossless_videodsp.c +++ b/libavcodec/lossless_videodsp.c @@ -98,6 +98,16 @@ static int add_left_pred_int16_c(uint16_t *dst, const uint16_t *src, unsigned ma return acc; } +static void add_gradient_pred_c(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width){ + int A, B, C, i; + + for (i = 0; i < width; i++) { + A = src[i - stride]; + B = src[i - (stride + 1)]; + C = src[i - 1]; + src[i] = (A - B + C + src[i]) & 0xFF; + } +} void ff_llviddsp_init(LLVidDSPContext *c) { @@ -106,6 +116,7 @@ void ff_llviddsp_init(LLVidDSPContext *c) c->add_left_pred = add_left_pred_c; c->add_left_pred_int16 = add_left_pred_int16_c; + c->add_gradient_pred = add_gradient_pred_c; if (ARCH_PPC) ff_llviddsp_init_ppc(c); diff --git a/libavcodec/lossless_videodsp.h b/libavcodec/lossless_videodsp.h index cecf0fe1e..8077898d1 100644 --- a/libavcodec/lossless_videodsp.h +++ b/libavcodec/lossless_videodsp.h @@ -29,7 +29,7 @@ #include "libavutil/cpu.h" typedef struct LLVidDSPContext { - void (*add_bytes)(uint8_t *dst /* align 16 */, uint8_t *src /* align 16 */, + void (*add_bytes)(uint8_t *dst /* align 32 */, uint8_t *src /* align 32 */, ptrdiff_t w); void (*add_median_pred)(uint8_t *dst, const uint8_t *top, const uint8_t *diff, ptrdiff_t w, @@ -39,6 +39,7 @@ typedef struct LLVidDSPContext { int (*add_left_pred_int16)(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned left); + void (*add_gradient_pred)(uint8_t *src /* align 32 */, const ptrdiff_t stride, const ptrdiff_t width); } LLVidDSPContext; void ff_llviddsp_init(LLVidDSPContext *llviddsp); diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c index 3c1a89077..9c6e1ba1b 100644 --- a/libavcodec/magicyuv.c +++ b/libavcodec/magicyuv.c @@ -280,11 +280,9 @@ static int magy_decode_slice10(AVCodecContext *avctx, void *tdata, case GRADIENT: dst = (uint16_t *)p->data[i] + j * sheight * stride; s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); - left = lefttop = 0; dst += stride; if (interlaced) { s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); - left = lefttop = 0; dst += stride; } for (k = 1 + interlaced; k < height; k++) { @@ -302,14 +300,13 @@ static int magy_decode_slice10(AVCodecContext *avctx, void *tdata, break; case MEDIAN: dst = (uint16_t *)p->data[i] + j * sheight * stride; - lefttop = left = dst[0]; s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); dst += stride; if (interlaced) { - lefttop = left = dst[0]; s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); dst += stride; } + lefttop = left = dst[0]; for (k = 1 + interlaced; k < height; k++) { magicyuv_median_pred16(dst, dst - fake_stride, dst, width, &left, &lefttop, max); lefttop = left = dst[0]; @@ -348,7 +345,7 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata, MagicYUVContext *s = avctx->priv_data; int interlaced = s->interlaced; AVFrame *p = s->p; - int i, k, x; + int i, k, x, min_width; GetBitContext gb; uint8_t *dst; @@ -411,36 +408,36 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata, case GRADIENT: dst = p->data[i] + j * sheight * stride; s->llviddsp.add_left_pred(dst, dst, width, 0); - left = lefttop = 0; dst += stride; if (interlaced) { s->llviddsp.add_left_pred(dst, dst, width, 0); - left = lefttop = 0; dst += stride; } + min_width = FFMIN(width, 32); for (k = 1 + interlaced; k < height; k++) { top = dst[-fake_stride]; left = top + dst[0]; dst[0] = left; - for (x = 1; x < width; x++) { + for (x = 1; x < min_width; x++) { /* dsp need aligned 32 */ top = dst[x - fake_stride]; lefttop = dst[x - (fake_stride + 1)]; left += top - lefttop + dst[x]; dst[x] = left; } + if (width > 32) + s->llviddsp.add_gradient_pred(dst + 32, fake_stride, width - 32); dst += stride; } break; case MEDIAN: dst = p->data[i] + j * sheight * stride; - lefttop = left = dst[0]; s->llviddsp.add_left_pred(dst, dst, width, 0); dst += stride; if (interlaced) { - lefttop = left = dst[0]; s->llviddsp.add_left_pred(dst, dst, width, 0); dst += stride; } + lefttop = left = dst[0]; for (k = 1 + interlaced; k < height; k++) { s->llviddsp.add_median_pred(dst, dst - fake_stride, dst, width, &left, &lefttop); diff --git a/libavcodec/magicyuvenc.c b/libavcodec/magicyuvenc.c new file mode 100644 index 000000000..c784221e1 --- /dev/null +++ b/libavcodec/magicyuvenc.c @@ -0,0 +1,558 @@ +/* + * MagicYUV encoder + * 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 +#include + +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/qsort.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "put_bits.h" +#include "internal.h" +#include "thread.h" +#include "lossless_videoencdsp.h" + +typedef enum Prediction { + LEFT = 1, + GRADIENT, + MEDIAN, +} Prediction; + +typedef struct HuffEntry { + uint8_t sym; + uint8_t len; + uint32_t code; +} HuffEntry; + +typedef struct PTable { + int value; ///< input value + int64_t prob; ///< number of occurences of this value in input +} PTable; + +typedef struct MagicYUVContext { + const AVClass *class; + int frame_pred; + PutBitContext pb; + int planes; + uint8_t format; + AVFrame *p; + int max; + int slice_height; + int nb_slices; + int correlate; + int hshift[4]; + int vshift[4]; + uint8_t *slices[4]; + unsigned slice_pos[4]; + unsigned tables_size; + HuffEntry he[4][256]; + LLVidEncDSPContext llvidencdsp; + void (*predict)(struct MagicYUVContext *s, uint8_t *src, uint8_t *dst, + ptrdiff_t stride, int width, int height); +} MagicYUVContext; + +static void left_predict(MagicYUVContext *s, + uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int width, int height) +{ + uint8_t prev = 0; + int i, j; + + for (i = 0; i < width; i++) { + dst[i] = src[i] - prev; + prev = src[i]; + } + dst += width; + src += stride; + for (j = 1; j < height; j++) { + prev = src[-stride]; + for (i = 0; i < width; i++) { + dst[i] = src[i] - prev; + prev = src[i]; + } + dst += width; + src += stride; + } +} + +static void gradient_predict(MagicYUVContext *s, + uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int width, int height) +{ + int left = 0, top, lefttop; + int i, j; + + for (i = 0; i < width; i++) { + dst[i] = src[i] - left; + left = src[i]; + } + dst += width; + src += stride; + for (j = 1; j < height; j++) { + top = src[-stride]; + left = src[0] - top; + dst[0] = left; + for (i = 1; i < width; i++) { + top = src[i - stride]; + lefttop = src[i - (stride + 1)]; + left = src[i-1]; + dst[i] = (src[i] - top) - left + lefttop; + } + dst += width; + src += stride; + } +} + +static void median_predict(MagicYUVContext *s, + uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int width, int height) +{ + int left = 0, lefttop; + int i, j; + + for (i = 0; i < width; i++) { + dst[i] = src[i] - left; + left = src[i]; + } + dst += width; + src += stride; + for (j = 1; j < height; j++) { + left = lefttop = src[-stride]; + s->llvidencdsp.sub_median_pred(dst, src - stride, src, width, &left, &lefttop); + dst += width; + src += stride; + } +} + +static av_cold int magy_encode_init(AVCodecContext *avctx) +{ + MagicYUVContext *s = avctx->priv_data; + int i; + + switch (avctx->pix_fmt) { + case AV_PIX_FMT_GBRP: + avctx->codec_tag = MKTAG('M', '8', 'R', 'G'); + s->correlate = 1; + s->format = 0x65; + break; + case AV_PIX_FMT_GBRAP: + avctx->codec_tag = MKTAG('M', '8', 'R', 'A'); + s->correlate = 1; + s->format = 0x66; + break; + case AV_PIX_FMT_YUV420P: + avctx->codec_tag = MKTAG('M', '8', 'Y', '0'); + s->hshift[1] = + s->vshift[1] = + s->hshift[2] = + s->vshift[2] = 1; + s->format = 0x69; + break; + case AV_PIX_FMT_YUV422P: + avctx->codec_tag = MKTAG('M', '8', 'Y', '2'); + s->hshift[1] = + s->hshift[2] = 1; + s->format = 0x68; + break; + case AV_PIX_FMT_YUV444P: + avctx->codec_tag = MKTAG('M', '8', 'Y', '4'); + s->format = 0x67; + break; + case AV_PIX_FMT_YUVA444P: + avctx->codec_tag = MKTAG('M', '8', 'Y', 'A'); + s->format = 0x6a; + break; + case AV_PIX_FMT_GRAY8: + avctx->codec_tag = MKTAG('M', '8', 'G', '0'); + s->format = 0x6b; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", + avctx->pix_fmt); + return AVERROR_INVALIDDATA; + } + + ff_llvidencdsp_init(&s->llvidencdsp); + + s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); + + s->nb_slices = 1; + + for (i = 0; i < s->planes; i++) { + s->slices[i] = av_malloc(avctx->width * (avctx->height + 2) + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!s->slices[i]) { + av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer.\n"); + return AVERROR(ENOMEM); + } + } + + switch (s->frame_pred) { + case LEFT: s->predict = left_predict; break; + case GRADIENT: s->predict = gradient_predict; break; + case MEDIAN: s->predict = median_predict; break; + } + + return 0; +} + +static int magy_huff_cmp_len(const void *a, const void *b) +{ + const HuffEntry *aa = a, *bb = b; + return (aa->len - bb->len) * 256 + aa->sym - bb->sym; +} + +static int huff_cmp_sym(const void *a, const void *b) +{ + const HuffEntry *aa = a, *bb = b; + return bb->sym - aa->sym; +} + +static void calculate_codes(HuffEntry *he) +{ + uint32_t code; + int i; + + AV_QSORT(he, 256, HuffEntry, magy_huff_cmp_len); + + code = 1; + for (i = 255; i >= 0; i--) { + he[i].code = code >> (32 - he[i].len); + code += 0x80000000u >> (he[i].len - 1); + } + + AV_QSORT(he, 256, HuffEntry, huff_cmp_sym); +} + +static void count_usage(uint8_t *src, int width, + int height, PTable *counts) +{ + int i, j; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + counts[src[i]].prob++; + } + src += width; + } +} + +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; + +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; +} + +static void magy_huffman_compute_bits(PTable *prob_table, HuffEntry *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]]++; + } + + for (i = 0; i < size; i++) { + distincts[i].sym = i; + distincts[i].len = nbits[i]; + } +} + +static int encode_table(AVCodecContext *avctx, uint8_t *dst, + int width, int height, + PutBitContext *pb, HuffEntry *he) +{ + PTable counts[256] = { {0} }; + int i; + + count_usage(dst, width, height, counts); + + for (i = 0; i < 256; i++) { + counts[i].prob++; + counts[i].value = 255 - i; + } + + magy_huffman_compute_bits(counts, he, 256, 16); + + calculate_codes(he); + + for (i = 0; i < 256; i++) { + put_bits(pb, 1, 0); + put_bits(pb, 7, he[i].len); + } + + return 0; +} + +static int encode_slice(uint8_t *src, uint8_t *dst, int dst_size, + int width, int height, HuffEntry *he, int prediction) +{ + PutBitContext pb; + int i, j; + int count; + + init_put_bits(&pb, dst, dst_size); + + put_bits(&pb, 8, 0); + put_bits(&pb, 8, prediction); + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + const int idx = src[i]; + put_bits(&pb, he[idx].len, he[idx].code); + } + + src += width; + } + + count = put_bits_count(&pb) & 0x1F; + + if (count) + put_bits(&pb, 32 - count, 0); + + count = put_bits_count(&pb); + + flush_put_bits(&pb); + + return count >> 3; +} + +static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + MagicYUVContext *s = avctx->priv_data; + PutByteContext pb; + const int width = avctx->width, height = avctx->height; + int pos, slice, i, j, ret = 0; + + ret = ff_alloc_packet2(avctx, pkt, (256 + 4 * s->nb_slices + width * height) * + s->planes + 256, 0); + if (ret < 0) + return ret; + + bytestream2_init_writer(&pb, pkt->data, pkt->size); + bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32(&pb, 32); + bytestream2_put_byte(&pb, 7); + bytestream2_put_byte(&pb, s->format); + bytestream2_put_byte(&pb, 0); + bytestream2_put_byte(&pb, 0); + bytestream2_put_le32(&pb, 0); + + bytestream2_put_le32(&pb, avctx->width); + bytestream2_put_le32(&pb, avctx->height); + bytestream2_put_le32(&pb, avctx->width); + bytestream2_put_le32(&pb, avctx->height); + bytestream2_put_le32(&pb, 0); + + for (i = 0; i < s->planes; i++) { + bytestream2_put_le32(&pb, 0); + for (j = 1; j < s->nb_slices; j++) { + bytestream2_put_le32(&pb, 0); + } + } + + bytestream2_put_byte(&pb, s->planes); + + for (i = 0; i < s->planes; i++) { + for (slice = 0; slice < s->nb_slices; slice++) { + bytestream2_put_byte(&pb, i); + } + } + + if (s->correlate) { + uint8_t *r, *g, *b; + AVFrame *p = av_frame_clone(frame); + + g = p->data[0]; + b = p->data[1]; + r = p->data[2]; + + for (i = 0; i < height; i++) { + s->llvidencdsp.diff_bytes(b, b, g, width); + s->llvidencdsp.diff_bytes(r, r, g, width); + g += p->linesize[0]; + b += p->linesize[1]; + r += p->linesize[2]; + } + + FFSWAP(uint8_t*, p->data[0], p->data[1]); + FFSWAP(int, p->linesize[0], p->linesize[1]); + + for (i = 0; i < s->planes; i++) { + for (slice = 0; slice < s->nb_slices; slice++) { + s->predict(s, p->data[i], s->slices[i], p->linesize[i], + p->width, p->height); + } + } + + av_frame_free(&p); + } else { + for (i = 0; i < s->planes; i++) { + for (slice = 0; slice < s->nb_slices; slice++) { + s->predict(s, frame->data[i], s->slices[i], frame->linesize[i], + AV_CEIL_RSHIFT(frame->width, s->hshift[i]), + AV_CEIL_RSHIFT(frame->height, s->vshift[i])); + } + } + } + + init_put_bits(&s->pb, pkt->data + bytestream2_tell_p(&pb), bytestream2_get_bytes_left_p(&pb)); + + for (i = 0; i < s->planes; i++) { + encode_table(avctx, s->slices[i], + AV_CEIL_RSHIFT(frame->width, s->hshift[i]), + AV_CEIL_RSHIFT(frame->height, s->vshift[i]), + &s->pb, s->he[i]); + } + s->tables_size = (put_bits_count(&s->pb) + 7) >> 3; + bytestream2_skip_p(&pb, s->tables_size); + + for (i = 0; i < s->planes; i++) { + unsigned slice_size; + + s->slice_pos[i] = bytestream2_tell_p(&pb); + slice_size = encode_slice(s->slices[i], pkt->data + bytestream2_tell_p(&pb), + bytestream2_get_bytes_left_p(&pb), + AV_CEIL_RSHIFT(frame->width, s->hshift[i]), + AV_CEIL_RSHIFT(frame->height, s->vshift[i]), + s->he[i], s->frame_pred); + bytestream2_skip_p(&pb, slice_size); + } + + pos = bytestream2_tell_p(&pb); + bytestream2_seek_p(&pb, 32, SEEK_SET); + bytestream2_put_le32(&pb, s->slice_pos[0] - 32); + for (i = 0; i < s->planes; i++) { + bytestream2_put_le32(&pb, s->slice_pos[i] - 32); + } + bytestream2_seek_p(&pb, pos, SEEK_SET); + + pkt->size = bytestream2_tell_p(&pb); + pkt->flags |= AV_PKT_FLAG_KEY; + + *got_packet = 1; + + return 0; +} + +static av_cold int magy_encode_close(AVCodecContext *avctx) +{ + MagicYUVContext *s = avctx->priv_data; + int i; + + for (i = 0; i < s->planes; i++) + av_freep(&s->slices[i]); + + return 0; +} + +#define OFFSET(x) offsetof(MagicYUVContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, {.i64=LEFT}, LEFT, MEDIAN, VE, "pred" }, + { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LEFT }, 0, 0, VE, "pred" }, + { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = GRADIENT }, 0, 0, VE, "pred" }, + { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MEDIAN }, 0, 0, VE, "pred" }, + { NULL}, +}; + +static const AVClass magicyuv_class = { + .class_name = "magicyuv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_magicyuv_encoder = { + .name = "magicyuv", + .long_name = NULL_IF_CONFIG_SMALL("MagicYUV video"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MAGICYUV, + .priv_data_size = sizeof(MagicYUVContext), + .priv_class = &magicyuv_class, + .init = magy_encode_init, + .close = magy_encode_close, + .encode2 = magy_encode_frame, + .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_NONE + }, +}; diff --git a/libavcodec/mdct_fixed.c b/libavcodec/mdct_fixed.c index a32cb00ca..aabf0c88f 100644 --- a/libavcodec/mdct_fixed.c +++ b/libavcodec/mdct_fixed.c @@ -39,13 +39,13 @@ void ff_mdct_calcw_c(FFTContext *s, FFTDouble *out, const FFTSample *input) /* pre rotation */ for(i=0;i> 6) +# define RSCALE(x, y) ((int)((x) + (unsigned)(y) + 32) >> 6) #else /* FFT_FIXED_32 */ -# define RSCALE(x) ((x) >> 1) +# define RSCALE(x, y) ((int)((x) + (unsigned)(y)) >> 1) #endif /* FFT_FIXED_32 */ #endif @@ -181,13 +181,13 @@ void ff_mdct_calc_c(FFTContext *s, FFTSample *out, const FFTSample *input) /* pre rotation */ for(i=0;i diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index f34450a6d..dbc37bf46 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -274,6 +274,7 @@ struct FFAMediaCodec { struct JNIAMediaCodecFields jfields; jobject object; + jobject buffer_info; jobject input_buffers; jobject output_buffers; @@ -1132,13 +1133,19 @@ fail: return ret; } -FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) +#define CREATE_CODEC_BY_NAME 0 +#define CREATE_DECODER_BY_TYPE 1 +#define CREATE_ENCODER_BY_TYPE 2 + +static inline FFAMediaCodec *codec_create(int method, const char *arg) { int ret = -1; JNIEnv *env = NULL; FFAMediaCodec *codec = NULL; - jstring codec_name = NULL; + jstring jarg = NULL; jobject object = NULL; + jobject buffer_info = NULL; + jmethodID create_id = NULL; codec = av_mallocz(sizeof(FFAMediaCodec)); if (!codec) { @@ -1156,12 +1163,23 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) goto fail; } - codec_name = ff_jni_utf_chars_to_jstring(env, name, codec); - if (!codec_name) { + jarg = ff_jni_utf_chars_to_jstring(env, arg, codec); + if (!jarg) { goto fail; } - object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_by_codec_name_id, codec_name); + switch (method) { + case CREATE_CODEC_BY_NAME: create_id = codec->jfields.create_by_codec_name_id; break; + case CREATE_DECODER_BY_TYPE: create_id = codec->jfields.create_decoder_by_type_id; break; + case CREATE_ENCODER_BY_TYPE: create_id = codec->jfields.create_encoder_by_type_id; break; + default: + av_assert0(0); + } + + object = (*env)->CallStaticObjectMethod(env, + codec->jfields.mediacodec_class, + create_id, + jarg); if (ff_jni_exception_check(env, 1, codec) < 0) { goto fail; } @@ -1179,17 +1197,39 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) codec->has_get_i_o_buffer = 1; } + buffer_info = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id); + if (ff_jni_exception_check(env, 1, codec) < 0) { + goto fail; + } + + codec->buffer_info = (*env)->NewGlobalRef(env, buffer_info); + if (!codec->buffer_info) { + goto fail; + } + ret = 0; fail: - if (codec_name) { - (*env)->DeleteLocalRef(env, codec_name); + if (jarg) { + (*env)->DeleteLocalRef(env, jarg); } if (object) { (*env)->DeleteLocalRef(env, object); } + if (buffer_info) { + (*env)->DeleteLocalRef(env, buffer_info); + } + if (ret < 0) { + if (codec->object) { + (*env)->DeleteGlobalRef(env, codec->object); + } + + if (codec->buffer_info) { + (*env)->DeleteGlobalRef(env, codec->buffer_info); + } + ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); av_freep(&codec); } @@ -1197,135 +1237,15 @@ fail: return codec; } -FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) -{ - int ret = -1; - JNIEnv *env = NULL; - FFAMediaCodec *codec = NULL; - jstring mime_type = NULL; - jobject object = NULL; +#define DECLARE_FF_AMEDIACODEC_CREATE_FUNC(name, method) \ +FFAMediaCodec *ff_AMediaCodec_##name(const char *arg) \ +{ \ + return codec_create(method, arg); \ +} \ - codec = av_mallocz(sizeof(FFAMediaCodec)); - if (!codec) { - return NULL; - } - codec->class = &amediacodec_class; - - env = ff_jni_get_env(codec); - if (!env) { - av_freep(&codec); - return NULL; - } - - if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) { - goto fail; - } - - mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec); - if (!mime_type) { - goto fail; - } - - object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_decoder_by_type_id, mime_type); - if (ff_jni_exception_check(env, 1, codec) < 0) { - goto fail; - } - - codec->object = (*env)->NewGlobalRef(env, object); - if (!codec->object) { - goto fail; - } - - if (codec_init_static_fields(codec) < 0) { - goto fail; - } - - if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) { - codec->has_get_i_o_buffer = 1; - } - - ret = 0; -fail: - if (mime_type) { - (*env)->DeleteLocalRef(env, mime_type); - } - - if (object) { - (*env)->DeleteLocalRef(env, object); - } - - if (ret < 0) { - ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); - av_freep(&codec); - } - - return codec; -} - -FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) -{ - int ret = -1; - JNIEnv *env = NULL; - FFAMediaCodec *codec = NULL; - jstring mime_type = NULL; - jobject object = NULL; - - codec = av_mallocz(sizeof(FFAMediaCodec)); - if (!codec) { - return NULL; - } - codec->class = &amediacodec_class; - - env = ff_jni_get_env(codec); - if (!env) { - av_freep(&codec); - return NULL; - } - - if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) { - goto fail; - } - - mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec); - if (!mime_type) { - goto fail; - } - - object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_encoder_by_type_id, mime_type); - if (ff_jni_exception_check(env, 1, codec) < 0) { - goto fail; - } - - codec->object = (*env)->NewGlobalRef(env, object); - if (!codec->object) { - goto fail; - } - - if (codec_init_static_fields(codec) < 0) { - goto fail; - } - - if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) { - codec->has_get_i_o_buffer = 1; - } - - ret = 0; -fail: - if (mime_type) { - (*env)->DeleteLocalRef(env, mime_type); - } - - if (object) { - (*env)->DeleteLocalRef(env, object); - } - - if (ret < 0) { - ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); - av_freep(&codec); - } - - return codec; -} +DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createCodecByName, CREATE_CODEC_BY_NAME) +DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createDecoderByType, CREATE_DECODER_BY_TYPE) +DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createEncoderByType, CREATE_ENCODER_BY_TYPE) int ff_AMediaCodec_delete(FFAMediaCodec* codec) { @@ -1347,6 +1267,9 @@ int ff_AMediaCodec_delete(FFAMediaCodec* codec) (*env)->DeleteGlobalRef(env, codec->object); codec->object = NULL; + (*env)->DeleteGlobalRef(env, codec->buffer_info); + codec->buffer_info = NULL; + ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); av_freep(&codec); @@ -1514,48 +1437,31 @@ ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBu int ret = 0; JNIEnv *env = NULL; - jobject mediainfo = NULL; - JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); - mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id); + ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, codec->buffer_info, timeoutUs); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs); + info->flags = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.flags_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id); + info->offset = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.offset_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id); + info->presentationTimeUs = (*env)->GetLongField(env, codec->buffer_info, codec->jfields.presentation_time_us_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id); + info->size = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.size_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; - } - - info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id); - if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; - } -fail: - if (mediainfo) { - (*env)->DeleteLocalRef(env, mediainfo); + return AVERROR_EXTERNAL; } return ret; diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index 6962ce247..6c5d3ddd7 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -31,8 +31,10 @@ #include "libavutil/pixfmt.h" #include "avcodec.h" +#include "decode.h" #include "h264_parse.h" #include "hevc_parse.h" +#include "hwaccel.h" #include "internal.h" #include "mediacodec_wrapper.h" #include "mediacodecdec_common.h" @@ -182,7 +184,7 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int ret; HEVCParamSets ps; - HEVCSEIContext sei; + HEVCSEI sei; const HEVCVPS *vps = NULL; const HEVCPPS *pps = NULL; @@ -414,38 +416,13 @@ done: return ret; } - -static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *pkt) +static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) { MediaCodecH264DecContext *s = avctx->priv_data; - - return ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, pkt); -} - -static int mediacodec_decode_frame(AVCodecContext *avctx, void *data, - int *got_frame, AVPacket *avpkt) -{ - MediaCodecH264DecContext *s = avctx->priv_data; - AVFrame *frame = data; int ret; - - /* buffer the input packet */ - if (avpkt->size) { - AVPacket input_pkt = { 0 }; - - if (av_fifo_space(s->fifo) < sizeof(input_pkt)) { - ret = av_fifo_realloc2(s->fifo, - av_fifo_size(s->fifo) + sizeof(input_pkt)); - if (ret < 0) - return ret; - } - - ret = av_packet_ref(&input_pkt, avpkt); - if (ret < 0) - return ret; - av_fifo_generic_write(s->fifo, &input_pkt, sizeof(input_pkt), NULL); - } + int got_frame = 0; + int is_eof = 0; + AVPacket pkt = { 0 }; /* * MediaCodec.flush() discards both input and output buffers, thus we @@ -469,26 +446,57 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data, */ if (ff_mediacodec_dec_is_flushing(avctx, s->ctx)) { if (!ff_mediacodec_dec_flush(avctx, s->ctx)) { - return avpkt->size; + return AVERROR(EAGAIN); } } + ret = ff_decode_get_packet(avctx, &pkt); + if (ret == AVERROR_EOF) + is_eof = 1; + else if (ret == AVERROR(EAGAIN)) + ; /* no input packet, but fallthrough to check for pending frames */ + else if (ret < 0) + return ret; + + /* buffer the input packet */ + if (pkt.size) { + if (av_fifo_space(s->fifo) < sizeof(pkt)) { + ret = av_fifo_realloc2(s->fifo, + av_fifo_size(s->fifo) + sizeof(pkt)); + if (ret < 0) { + av_packet_unref(&pkt); + return ret; + } + } + av_fifo_generic_write(s->fifo, &pkt, sizeof(pkt), NULL); + } + /* process buffered data */ - while (!*got_frame) { + while (!got_frame) { /* prepare the input data */ if (s->buffered_pkt.size <= 0) { av_packet_unref(&s->buffered_pkt); /* no more data */ if (av_fifo_size(s->fifo) < sizeof(AVPacket)) { - return avpkt->size ? avpkt->size : - ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, avpkt); + AVPacket null_pkt = { 0 }; + if (is_eof) { + ret = ff_mediacodec_dec_decode(avctx, s->ctx, frame, + &got_frame, &null_pkt); + if (ret < 0) + return ret; + else if (got_frame) + return 0; + else + return AVERROR_EOF; + } + return AVERROR(EAGAIN); } av_fifo_generic_read(s->fifo, &s->buffered_pkt, sizeof(s->buffered_pkt), NULL); } - ret = mediacodec_process_data(avctx, frame, got_frame, &s->buffered_pkt); + ret = ff_mediacodec_dec_decode(avctx, s->ctx, frame, &got_frame, &s->buffered_pkt); if (ret < 0) return ret; @@ -496,7 +504,7 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data, s->buffered_pkt.data += ret; } - return avpkt->size; + return 0; } static void mediacodec_decode_flush(AVCodecContext *avctx) @@ -515,6 +523,19 @@ static void mediacodec_decode_flush(AVCodecContext *avctx) ff_mediacodec_dec_flush(avctx, s->ctx); } +static const AVCodecHWConfigInternal *mediacodec_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_MEDIACODEC, + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC | + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, + .device_type = AV_HWDEVICE_TYPE_MEDIACODEC, + }, + .hwaccel = NULL, + }, + NULL +}; + #if CONFIG_H264_MEDIACODEC_DECODER AVCodec ff_h264_mediacodec_decoder = { .name = "h264_mediacodec", @@ -523,12 +544,14 @@ AVCodec ff_h264_mediacodec_decoder = { .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(MediaCodecH264DecContext), .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, + .receive_frame = mediacodec_receive_frame, .flush = mediacodec_decode_flush, .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, .bsfs = "h264_mp4toannexb", + .hw_configs = mediacodec_hw_configs, + .wrapper_name = "mediacodec", }; #endif @@ -540,12 +563,14 @@ AVCodec ff_hevc_mediacodec_decoder = { .id = AV_CODEC_ID_HEVC, .priv_data_size = sizeof(MediaCodecH264DecContext), .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, + .receive_frame = mediacodec_receive_frame, .flush = mediacodec_decode_flush, .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, .bsfs = "hevc_mp4toannexb", + .hw_configs = mediacodec_hw_configs, + .wrapper_name = "mediacodec", }; #endif @@ -557,11 +582,13 @@ AVCodec ff_mpeg2_mediacodec_decoder = { .id = AV_CODEC_ID_MPEG2VIDEO, .priv_data_size = sizeof(MediaCodecH264DecContext), .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, + .receive_frame = mediacodec_receive_frame, .flush = mediacodec_decode_flush, .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, + .hw_configs = mediacodec_hw_configs, + .wrapper_name = "mediacodec", }; #endif @@ -573,11 +600,13 @@ AVCodec ff_mpeg4_mediacodec_decoder = { .id = AV_CODEC_ID_MPEG4, .priv_data_size = sizeof(MediaCodecH264DecContext), .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, + .receive_frame = mediacodec_receive_frame, .flush = mediacodec_decode_flush, .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, + .hw_configs = mediacodec_hw_configs, + .wrapper_name = "mediacodec", }; #endif @@ -589,11 +618,13 @@ AVCodec ff_vp8_mediacodec_decoder = { .id = AV_CODEC_ID_VP8, .priv_data_size = sizeof(MediaCodecH264DecContext), .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, + .receive_frame = mediacodec_receive_frame, .flush = mediacodec_decode_flush, .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, + .hw_configs = mediacodec_hw_configs, + .wrapper_name = "mediacodec", }; #endif @@ -605,10 +636,12 @@ AVCodec ff_vp9_mediacodec_decoder = { .id = AV_CODEC_ID_VP9, .priv_data_size = sizeof(MediaCodecH264DecContext), .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, + .receive_frame = mediacodec_receive_frame, .flush = mediacodec_decode_flush, .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, + .hw_configs = mediacodec_hw_configs, + .wrapper_name = "mediacodec", }; #endif diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index afa054f83..a9147f3a0 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -24,6 +24,7 @@ #include #include "libavutil/common.h" +#include "libavutil/hwcontext_mediacodec.h" #include "libavutil/mem.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" @@ -476,7 +477,18 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, if (pix_fmt == AV_PIX_FMT_MEDIACODEC) { AVMediaCodecContext *user_ctx = avctx->hwaccel_context; - if (user_ctx && user_ctx->surface) { + if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data); + if (device_ctx->type == AV_HWDEVICE_TYPE_MEDIACODEC) { + if (device_ctx->hwctx) { + AVMediaCodecDeviceContext *mediacodec_ctx = (AVMediaCodecDeviceContext *)device_ctx->hwctx; + s->surface = ff_mediacodec_surface_ref(mediacodec_ctx->surface, avctx); + av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface); + } + } + } + + if (!s->surface && user_ctx && user_ctx->surface) { s->surface = ff_mediacodec_surface_ref(user_ctx->surface, avctx); av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface); } @@ -757,45 +769,3 @@ int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, MediaCodecDecContext *s { return s->flushing; } - -AVHWAccel ff_h264_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_hevc_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_HEVC, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_mpeg2_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_mpeg4_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_vp8_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP8, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_vp9_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP9, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; diff --git a/libavcodec/mips/h264chroma_msa.c b/libavcodec/mips/h264chroma_msa.c index b8fcf6d01..4c2576119 100644 --- a/libavcodec/mips/h264chroma_msa.c +++ b/libavcodec/mips/h264chroma_msa.c @@ -839,12 +839,11 @@ static void avc_chroma_hv_8w_msa(uint8_t *src, uint8_t *dst, int32_t stride, } } -static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint16_t out0, out1; - uint32_t load0, load1; v16i8 src0, src1; v16u8 dst_data = { 0 }; v8u16 res_r; @@ -856,12 +855,13 @@ static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[0]); - LD_SB2(src, src_stride, src0, src1); + LD_SB2(src, stride, src0, src1); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + out0 = LH(dst); + out1 = LH(dst + stride); - INSERT_W2_UB(load0, load1, dst_data); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, out0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, out1); src0 = __msa_vshf_b(mask, src1, src0); @@ -877,30 +877,34 @@ static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, out1 = __msa_copy_u_h((v8i16) dst_data, 2); SH(out0, dst); - dst += dst_stride; + dst += stride; SH(out1, dst); } -static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { + uint16_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0, dst_data = { 0 }; v8u16 res_r; - v16i8 res, mask; + v16i8 mask; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); mask = LD_SB(&chroma_mask_arr[64]); - LD_UB4(src, src_stride, src0, src1, src2, src3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); + LD_UB4(src, stride, src0, src1, src2, src3); + tp0 = LH(dst); + tp1 = LH(dst + stride); + tp2 = LH(dst + 2 * stride); + tp3 = LH(dst + 3 * stride); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, tp0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 1, tp1); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, tp2); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 3, tp3); VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); @@ -911,75 +915,26 @@ static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); res_r = __msa_sat_u_h(res_r, 7); - res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - dst0 = __msa_aver_u_b((v16u8) res, dst0); + dst0 = (v16u8) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); + dst0 = __msa_aver_u_b(dst0, dst_data); - ST2x4_UB(dst0, 0, dst, dst_stride); + ST2x4_UB(dst0, 0, dst, stride); } -static void avc_chroma_hz_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) -{ - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v8u16 res0_r, res1_r; - v16u8 res0, res1, mask; - v16i8 coeff_vec0 = __msa_fill_b(coeff0); - v16i8 coeff_vec1 = __msa_fill_b(coeff1); - v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - - mask = LD_UB(&chroma_mask_arr[64]); - - LD_UB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(dst, dst_stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); - - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 1, (v8i16) dst5); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 2, (v8i16) dst6); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 3, (v8i16) dst7); - - VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); - VSHF_B2_UB(src4, src5, src6, src7, mask, mask, src4, src6); - ILVR_D2_UB(src2, src0, src6, src4, src0, src4); - DOTP_UB2_UH(src0, src4, coeff_vec, coeff_vec, res0_r, res1_r); - - res0_r <<= 3; - res1_r <<= 3; - - SRARI_H2_UH(res0_r, res1_r, 6); - SAT_UH2_UH(res0_r, res1_r, 7); - PCKEV_B2_UB(res0_r, res0_r, res1_r, res1_r, res0, res1); - AVER_UB2_UB(res0, dst0, res1, dst4, dst0, dst4); - - ST2x4_UB(dst0, 0, dst, dst_stride); - dst += (4 * dst_stride); - ST2x4_UB(dst4, 0, dst, dst_stride); -} - -static void avc_chroma_hz_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_hz_and_aver_dst_2x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_hz_and_aver_dst_2x2_msa(src, dst, stride, coeff0, coeff1); } else if (4 == height) { - avc_chroma_hz_and_aver_dst_2x4_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else if (8 == height) { - avc_chroma_hz_and_aver_dst_2x8_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_hz_and_aver_dst_2x4_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint32_t load0, load1; v16i8 src0, src1; @@ -992,10 +947,9 @@ static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[0]); - LD_SB2(src, src_stride, src0, src1); + LD_SB2(src, stride, src0, src1); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + LW2(dst, stride, load0, load1); INSERT_W2_UB(load0, load1, dst_data); @@ -1008,84 +962,122 @@ static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); dst_data = __msa_aver_u_b((v16u8) res, dst_data); - ST4x2_UB(dst_data, dst, dst_stride); + ST4x2_UB(dst_data, dst, stride); } -static void avc_chroma_hz_and_aver_dst_4x4multiple_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint32_t coeff0, - uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t load0, load1; - uint32_t row; + uint32_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3; - v16u8 dst0 = { 0 }; - v16u8 dst1 = { 0 }; + v16u8 out, dst_data = { 0 }; + v16i8 mask; v8u16 res0_r, res1_r; - v16u8 res0, res1, mask; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - mask = LD_UB(&chroma_mask_arr[0]); + mask = LD_SB(&chroma_mask_arr[0]); - for (row = (height >> 2); row--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - load0 = LW(dst); - load1 = LW(dst + dst_stride); - - INSERT_W2_UB(load0, load1, dst0); - - load0 = LW(dst + 2 * dst_stride); - load1 = LW(dst + 3 * dst_stride); - - INSERT_W2_UB(load0, load1, dst1); - - VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); - DOTP_UB2_UH(src0, src2, coeff_vec, coeff_vec, res0_r, res1_r); - - res0_r <<= 3; - res1_r <<= 3; - - SRARI_H2_UH(res0_r, res1_r, 6); - SAT_UH2_UH(res0_r, res1_r, 7); - PCKEV_B2_UB(res0_r, res0_r, res1_r, res1_r, res0, res1); - AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); - - ST4x4_UB(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_UB4(src, stride, src0, src1, src2, src3); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst_data); + VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); + DOTP_UB2_UH(src0, src2, coeff_vec, coeff_vec, res0_r, res1_r); + res0_r <<= 3; + res1_r <<= 3; + SRARI_H2_UH(res0_r, res1_r, 6); + SAT_UH2_UH(res0_r, res1_r, 7); + out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); + out = __msa_aver_u_b(out, dst_data); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -static void avc_chroma_hz_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, out0, out1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; + v16i8 mask; + v8u16 res0, res1, res2, res3; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); + + mask = LD_SB(&chroma_mask_arr[0]); + + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); + VSHF_B2_UB(src4, src5, src6, src7, mask, mask, src4, src6); + DOTP_UB2_UH(src0, src2, coeff_vec, coeff_vec, res0, res1); + DOTP_UB2_UH(src4, src6, coeff_vec, coeff_vec, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST4x8_UB(out0, out1, dst, stride); +} + +static void avc_chroma_hz_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_hz_and_aver_dst_4x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else { - avc_chroma_hz_and_aver_dst_4x4multiple_msa(src, src_stride, - dst, dst_stride, - coeff0, coeff1, height); + avc_chroma_hz_and_aver_dst_4x2_msa(src, dst, stride, coeff0, coeff1); + } else if (4 == height) { + avc_chroma_hz_and_aver_dst_4x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_hz_and_aver_dst_4x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_hz_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t row; + uint64_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, out0, out1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; v8u16 res0, res1, res2, res3; - v16u8 dst0, dst1, dst2, dst3; + v16i8 mask; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); + + mask = LD_SB(&chroma_mask_arr[32]); + LD_UB4(src, stride, src0, src1, src2, src3); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + VSHF_B2_UB(src0, src0, src1, src1, mask, mask, src0, src1); + VSHF_B2_UB(src2, src2, src3, src3, mask, mask, src2, src3); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); +} + +static void avc_chroma_hz_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint64_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v8u16 res0, res1, res2, res3, res4, res5, res6, res7; v16i8 mask; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); @@ -1093,43 +1085,64 @@ static void avc_chroma_hz_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[32]); - for (row = height >> 2; row--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - VSHF_B2_UB(src0, src0, src1, src1, mask, mask, src0, src1); - VSHF_B2_UB(src2, src2, src3, src3, mask, mask, src2, src3); - DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, - coeff_vec, res0, res1, res2, res3); - SLLI_4V(res0, res1, res2, res3, 3); - SRARI_H4_UH(res0, res1, res2, res3, 6); - SAT_UH4_UH(res0, res1, res2, res3, 7); - PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + VSHF_B2_UB(src0, src0, src1, src1, mask, mask, src0, src1); + VSHF_B2_UB(src2, src2, src3, src3, mask, mask, src2, src3); + VSHF_B2_UB(src4, src4, src5, src5, mask, mask, src4, src5); + VSHF_B2_UB(src6, src6, src7, src7, mask, mask, src6, src7); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + DOTP_UB4_UH(src4, src5, src6, src7, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res4, res5, res6, res7); + SLLI_4V(res0, res1, res2, res3, 3); + SLLI_4V(res4, res5, res6, res7, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SRARI_H4_UH(res4, res5, res6, res7, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + SAT_UH4_UH(res4, res5, res6, res7, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} + +static void avc_chroma_hz_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) +{ + if (4 == height) { + avc_chroma_hz_and_aver_dst_8x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_hz_and_aver_dst_8x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_vt_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_vt_and_aver_dst_2x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint16_t out0, out1; - uint32_t load0, load1; v16i8 src0, src1, src2, tmp0, tmp1, res; v16u8 dst_data = { 0 }; + v8i16 out; v8u16 res_r; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - LD_SB3(src, src_stride, src0, src1, src2); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + LD_SB3(src, stride, src0, src1, src2); + out0 = LH(dst); + out1 = LH(dst + stride); - INSERT_W2_UB(load0, load1, dst_data); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, out0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, out1); ILVR_B2_SB(src1, src0, src2, src1, tmp0, tmp1); @@ -1139,20 +1152,20 @@ static void avc_chroma_vt_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); res_r = __msa_sat_u_h(res_r, 7); res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - dst_data = __msa_aver_u_b((v16u8) res, dst_data); - out0 = __msa_copy_u_h((v8i16) dst_data, 0); - out1 = __msa_copy_u_h((v8i16) dst_data, 2); + out = (v8i16) __msa_aver_u_b((v16u8) res, dst_data); + out0 = __msa_copy_u_h(out, 0); + out1 = __msa_copy_u_h(out, 2); SH(out0, dst); - dst += dst_stride; + dst += stride; SH(out1, dst); } -static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t load0, load1; + uint16_t tp0, tp1, tp2, tp3; v16i8 src0, src1, src2, src3, src4; v16u8 tmp0, tmp1, tmp2, tmp3; v8u16 res_r; @@ -1162,19 +1175,16 @@ static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); v16u8 dst_data = { 0 }; - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + LD_SB5(src, stride, src0, src1, src2, src3, src4); - load0 = LW(dst); - load1 = LW(dst + dst_stride); - - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, load0); - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 1, load1); - - load0 = LW(dst + 2 * dst_stride); - load1 = LW(dst + 3 * dst_stride); - - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, load0); - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 3, load1); + tp0 = LH(dst); + tp1 = LH(dst + stride); + tp2 = LH(dst + 2 * stride); + tp3 = LH(dst + 3 * stride); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, tp0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 1, tp1); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, tp2); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 3, tp3); ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, tmp0, tmp1, tmp2, tmp3); @@ -1190,102 +1200,26 @@ static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data); - ST2x4_UB(res, 0, dst, dst_stride); - dst += (4 * dst_stride); + ST2x4_UB(res, 0, dst, stride); } -static void avc_chroma_vt_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) -{ - uint32_t load0, load1, load2, load3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16u8 tmp0, tmp1, tmp2, tmp3; - v8i16 res; - v8u16 res_r; - v16i8 coeff_vec0 = __msa_fill_b(coeff0); - v16i8 coeff_vec1 = __msa_fill_b(coeff1); - v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - v16u8 dst_data0 = { 0 }; - v16u8 dst_data1 = { 0 }; - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - LD_SB4(src, src_stride, src5, src6, src7, src8); - - LW4(dst, dst_stride, load0, load1, load2, load3); - - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 0, load0); - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 1, load1); - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 2, load2); - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 3, load3); - - LW4(dst + 4 * dst_stride, dst_stride, load0, load1, load2, load3); - - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 0, load0); - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 1, load1); - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 2, load2); - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 3, load3); - - ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, - tmp0, tmp1, tmp2, tmp3); - - ILVR_W2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); - - tmp0 = (v16u8) __msa_ilvr_d((v2i64) tmp2, (v2i64) tmp0); - - res_r = __msa_dotp_u_h(tmp0, coeff_vec); - res_r <<= 3; - res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); - res_r = __msa_sat_u_h(res_r, 7); - - res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data0); - - ST2x4_UB(res, 0, dst, dst_stride); - dst += (4 * dst_stride); - - ILVR_B4_UB(src5, src4, src6, src5, src7, src6, src8, src7, - tmp0, tmp1, tmp2, tmp3); - - ILVR_W2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); - - tmp0 = (v16u8) __msa_ilvr_d((v2i64) tmp2, (v2i64) tmp0); - - res_r = __msa_dotp_u_h(tmp0, coeff_vec); - res_r <<= 3; - res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); - res_r = __msa_sat_u_h(res_r, 7); - - res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data1); - - ST2x4_UB(res, 0, dst, dst_stride); -} - -static void avc_chroma_vt_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_vt_and_aver_dst_2x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_vt_and_aver_dst_2x2_msa(src, dst, stride, coeff0, coeff1); } else if (4 == height) { - avc_chroma_vt_and_aver_dst_2x4_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else if (8 == height) { - avc_chroma_vt_and_aver_dst_2x8_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_vt_and_aver_dst_2x4_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint32_t load0, load1; - v16i8 src0, src1, src2, tmp0, tmp1; + v16u8 src0, src1, src2, tmp0, tmp1; v16u8 dst_data = { 0 }; v8u16 res_r; v16u8 res; @@ -1293,140 +1227,196 @@ static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - LD_SB3(src, src_stride, src0, src1, src2); + LD_UB3(src, stride, src0, src1, src2); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + LW2(dst, stride, load0, load1); INSERT_W2_UB(load0, load1, dst_data); - ILVR_B2_SB(src1, src0, src2, src1, tmp0, tmp1); + ILVR_B2_UB(src1, src0, src2, src1, tmp0, tmp1); - tmp0 = (v16i8) __msa_ilvr_d((v2i64) tmp1, (v2i64) tmp0); + tmp0 = (v16u8) __msa_ilvr_d((v2i64) tmp1, (v2i64) tmp0); - res_r = __msa_dotp_u_h((v16u8) tmp0, coeff_vec); + res_r = __msa_dotp_u_h(tmp0, coeff_vec); res_r <<= 3; res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); res_r = __msa_sat_u_h(res_r, 7); res = (v16u8) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); res = __msa_aver_u_b(res, dst_data); - ST4x2_UB(res, dst, dst_stride); + ST4x2_UB(res, dst, stride); } -static void avc_chroma_vt_and_aver_dst_4x4mul_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint32_t coeff0, - uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t load0, load1, row; - v16i8 src0, src1, src2, src3, src4; + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4; v16u8 tmp0, tmp1, tmp2, tmp3; v16u8 dst0 = { 0 }; - v16u8 dst1 = { 0 }; v8u16 res0_r, res1_r; - v16u8 res0, res1; + v16u8 out; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - src0 = LD_SB(src); - src += src_stride; - - for (row = (height >> 2); row--;) { - LD_SB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - - load0 = LW(dst); - load1 = LW(dst + dst_stride); - - INSERT_W2_UB(load0, load1, dst0); - load0 = LW(dst + 2 * dst_stride); - load1 = LW(dst + 3 * dst_stride); - INSERT_W2_UB(load0, load1, dst1); - - ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, - tmp0, tmp1, tmp2, tmp3); - ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); - DOTP_UB2_UH(tmp0, tmp2, coeff_vec, coeff_vec, res0_r, res1_r); - - res0_r <<= 3; - res1_r <<= 3; - - SRARI_H2_UH(res0_r, res1_r, 6); - SAT_UH2_UH(res0_r, res1_r, 7); - PCKEV_B2_UB(res0_r, res0_r, res1_r, res1_r, res0, res1); - AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); - - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - src0 = src4; - } + LD_UB5(src, stride, src0, src1, src2, src3, src4); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, tmp0, tmp1, tmp2, + tmp3); + ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); + DOTP_UB2_UH(tmp0, tmp2, coeff_vec, coeff_vec, res0_r, res1_r); + res0_r <<= 3; + res1_r <<= 3; + SRARI_H2_UH(res0_r, res1_r, 6); + SAT_UH2_UH(res0_r, res1_r, 7); + out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); + out = __msa_aver_u_b(out, dst0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -static void avc_chroma_vt_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, out0, out1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; + v8u16 res0, res1, res2, res3; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); + + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, tmp0, tmp1, tmp2, + tmp3); + ILVR_B4_UB(src5, src4, src6, src5, src7, src6, src8, src7, tmp4, tmp5, tmp6, + tmp7); + ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); + ILVR_D2_UB(tmp5, tmp4, tmp7, tmp6, tmp4, tmp6); + DOTP_UB2_UH(tmp0, tmp2, coeff_vec, coeff_vec, res0, res1); + DOTP_UB2_UH(tmp4, tmp6, coeff_vec, coeff_vec, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST4x8_UB(out0, out1, dst, stride); +} + +static void avc_chroma_vt_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_vt_and_aver_dst_4x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else { - avc_chroma_vt_and_aver_dst_4x4mul_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1, height); + avc_chroma_vt_and_aver_dst_4x2_msa(src, dst, stride, coeff0, coeff1); + } else if (4 == height) { + avc_chroma_vt_and_aver_dst_4x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_vt_and_aver_dst_4x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_vt_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t row; + uint64_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4; v16u8 out0, out1; v8u16 res0, res1, res2, res3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0 = { 0 }, dst1 = { 0 }; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - src0 = LD_UB(src); - src += src_stride; + LD_UB5(src, stride, src0, src1, src2, src3, src4); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, + src0, src1, src2, src3); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST8x4_UB(out0, out1, dst, stride); +} - for (row = height >> 2; row--;) { - LD_UB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, - src0, src1, src2, src3); - DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, - coeff_vec, res0, res1, res2, res3); - SLLI_4V(res0, res1, res2, res3, 3); - SRARI_H4_UH(res0, res1, res2, res3, 6); - SAT_UH4_UH(res0, res1, res2, res3, 7); - PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); +static void avc_chroma_vt_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint64_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v8u16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - dst += (4 * dst_stride); - src0 = src4; + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, + src0, src1, src2, src3); + ILVR_B4_UB(src5, src4, src6, src5, src7, src6, src8, src7, + src4, src5, src6, src7); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + DOTP_UB4_UH(src4, src5, src6, src7, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res4, res5, res6, res7); + SLLI_4V(res0, res1, res2, res3, 3); + SLLI_4V(res4, res5, res6, res7, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SRARI_H4_UH(res4, res5, res6, res7, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} + +static void avc_chroma_vt_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) +{ + if (4 == height) { + avc_chroma_vt_and_aver_dst_8x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_vt_and_aver_dst_8x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, uint32_t coef_ver1) { uint16_t out0, out1; - v16u8 dst0, dst1; + v16u8 dst0 = { 0 }; v16u8 src0, src1, src2; v8u16 res_hz0, res_hz1, res_vt0, res_vt1; v16i8 res, mask; @@ -1438,8 +1428,11 @@ static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[48]); - LD_UB3(src, src_stride, src0, src1, src2); - LD_UB2(dst, dst_stride, dst0, dst1); + LD_UB3(src, stride, src0, src1, src2); + out0 = LH(dst); + out1 = LH(dst + stride); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 0, out0); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 1, out1); VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); @@ -1448,26 +1441,26 @@ static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); res_vt0 = __msa_sat_u_h(res_vt0, 7); res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); dst0 = __msa_aver_u_b((v16u8) res, dst0); out0 = __msa_copy_u_h((v8i16) dst0, 0); out1 = __msa_copy_u_h((v8i16) dst0, 1); SH(out0, dst); - dst += dst_stride; + dst += stride; SH(out1, dst); } -static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, uint32_t coef_ver1) { + uint16_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4; v16u8 tmp0, tmp1, tmp2, tmp3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0 = { 0 }; v8u16 res_hz0, res_hz1, res_vt0, res_vt1; v16i8 res, mask; v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); @@ -1478,8 +1471,15 @@ static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[48]); - LD_UB5(src, src_stride, src0, src1, src2, src3, src4); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); + LD_UB5(src, stride, src0, src1, src2, src3, src4); + tp0 = LH(dst); + tp1 = LH(dst + stride); + tp2 = LH(dst + 2 * stride); + tp3 = LH(dst + 3 * stride); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 0, tp0); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 1, tp1); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 2, tp2); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 3, tp3); VSHF_B2_UB(src0, src1, src2, src3, mask, mask, tmp0, tmp1); VSHF_B2_UB(src1, src2, src3, src4, mask, mask, tmp2, tmp3); ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, src0, src1); @@ -1490,81 +1490,13 @@ static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); res_vt0 = __msa_sat_u_h(res_vt0, 7); res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); dst0 = __msa_aver_u_b((v16u8) res, dst0); - ST2x4_UB(dst0, 0, dst, dst_stride); + ST2x4_UB(dst0, 0, dst, stride); } -static void avc_chroma_hv_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coef_hor0, - uint32_t coef_hor1, - uint32_t coef_ver0, - uint32_t coef_ver1) -{ - v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16u8 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v16u8 tmp0, tmp1, tmp2, tmp3; - v8u16 res_hz0, res_hz1, res_vt0, res_vt1; - v16i8 res, mask; - v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); - v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); - v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); - v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); - v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); - - mask = LD_SB(&chroma_mask_arr[48]); - - LD_UB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - LD_UB4(src, src_stride, src5, src6, src7, src8); - - LD_UB8(dst, dst_stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); - - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 1, (v8i16) dst5); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 2, (v8i16) dst6); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 3, (v8i16) dst7); - - VSHF_B2_UB(src0, src1, src2, src3, mask, mask, tmp0, tmp1); - VSHF_B2_UB(src1, src2, src3, src4, mask, mask, tmp2, tmp3); - ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, src0, src1); - VSHF_B2_UB(src4, src5, src6, src7, mask, mask, tmp0, tmp1); - VSHF_B2_UB(src5, src6, src7, src8, mask, mask, tmp2, tmp3); - ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, src4, src5); - DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); - MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); - - res_vt0 += res_vt1; - res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); - res_vt0 = __msa_sat_u_h(res_vt0, 7); - res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst0 = __msa_aver_u_b((v16u8) res, dst0); - - ST2x4_UB(dst0, 0, dst, dst_stride); - dst += (4 * dst_stride); - - DOTP_UB2_UH(src4, src5, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); - MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); - - res_vt0 += res_vt1; - res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); - res_vt0 = __msa_sat_u_h(res_vt0, 7); - res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst4 = __msa_aver_u_b((v16u8) res, dst4); - - ST2x4_UB(dst4, 0, dst, dst_stride); -} - -static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, @@ -1572,31 +1504,26 @@ static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, int32_t height) { if (2 == height) { - avc_chroma_hv_and_aver_dst_2x2_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); + avc_chroma_hv_and_aver_dst_2x2_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } else if (4 == height) { - avc_chroma_hv_and_aver_dst_2x4_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); - } else if (8 == height) { - avc_chroma_hv_and_aver_dst_2x8_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); + avc_chroma_hv_and_aver_dst_2x4_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } } -static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, uint32_t coef_ver1) { + uint32_t tp0, tp1; v16u8 src0, src1, src2; - v16u8 dst0, dst1; + v16u8 dst0, dst_data = { 0 }; v8u16 res_hz0, res_hz1, res_vt0, res_vt1; - v16i8 res, mask; + v16i8 mask; v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); @@ -1605,8 +1532,9 @@ static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[0]); - LD_UB3(src, src_stride, src0, src1, src2); - LD_UB2(dst, dst_stride, dst0, dst1); + LD_UB3(src, stride, src0, src1, src2); + LW2(dst, stride, tp0, tp1); + INSERT_W2_UB(tp0, tp1, dst_data); VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); @@ -1614,26 +1542,22 @@ static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, res_vt0 += res_vt1; res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); res_vt0 = __msa_sat_u_h(res_vt0, 7); - res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst0 = __msa_aver_u_b((v16u8) res, dst0); + dst0 = (v16u8) __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); + dst0 = __msa_aver_u_b(dst0, dst_data); - ST4x2_UB(dst0, dst, dst_stride); + ST4x2_UB(dst0, dst, stride); } -static void avc_chroma_hv_and_aver_dst_4x4mul_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint32_t coef_hor0, - uint32_t coef_hor1, - uint32_t coef_ver0, - uint32_t coef_ver1, - int32_t height) +static void avc_chroma_hv_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) { - uint32_t row; + uint32_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4; - v16u8 dst0, dst1, dst2, dst3; + v16u8 out, dst_data = { 0 }; v8u16 res_hz0, res_hz1, res_hz2, res_hz3; v8u16 res_vt0, res_vt1, res_vt2, res_vt3; v16i8 mask; @@ -1642,45 +1566,78 @@ static void avc_chroma_hv_and_aver_dst_4x4mul_msa(uint8_t *src, v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); - v16u8 res0, res1; mask = LD_SB(&chroma_mask_arr[0]); - src0 = LD_UB(src); - src += src_stride; - - for (row = (height >> 2); row--;) { - LD_UB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); - VSHF_B2_UB(src2, src3, src3, src4, mask, mask, src2, src3); - DOTP_UB4_UH(src0, src1, src2, src3, coeff_hz_vec, coeff_hz_vec, - coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1, res_hz2, - res_hz3); - MUL4(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, - coeff_vt_vec1, res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, - res_vt3); - ADD2(res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt1); - SRARI_H2_UH(res_vt0, res_vt1, 6); - SAT_UH2_UH(res_vt0, res_vt1, 7); - PCKEV_B2_UB(res_vt0, res_vt0, res_vt1, res_vt1, res0, res1); - - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst1 = (v16u8) __msa_insve_w((v4i32) dst2, 1, (v4i32) dst3); - - AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); - - ST4x4_UB(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - src0 = src4; - } + LD_UB5(src, stride, src0, src1, src2, src3, src4); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst_data); + VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); + VSHF_B2_UB(src2, src3, src3, src4, mask, mask, src2, src3); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1, res_hz2, + res_hz3); + MUL4(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec1, + res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + ADD2(res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt1); + SRARI_H2_UH(res_vt0, res_vt1, 6); + SAT_UH2_UH(res_vt0, res_vt1, 7); + out = (v16u8) __msa_pckev_b((v16i8) res_vt1, (v16i8) res_vt0); + out = __msa_aver_u_b(out, dst_data); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8, res0, res1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; + v8u16 res_hz0, res_hz1, res_hz2, res_hz3, res_hz4, res_hz5, res_hz6, res_hz7; + v8u16 res_vt0, res_vt1, res_vt2, res_vt3, res_vt4, res_vt5, res_vt6, res_vt7; + v16i8 mask; + v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); + v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); + v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); + v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); + v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); + + mask = LD_SB(&chroma_mask_arr[0]); + + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); + VSHF_B2_UB(src2, src3, src3, src4, mask, mask, src2, src3); + VSHF_B2_UB(src4, src5, src5, src6, mask, mask, src4, src5); + VSHF_B2_UB(src6, src7, src7, src8, mask, mask, src6, src7); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1, res_hz2, res_hz3); + DOTP_UB4_UH(src4, src5, src6, src7, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz4, res_hz5, res_hz6, res_hz7); + MUL4(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec1, + res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + MUL4(res_hz4, coeff_vt_vec1, res_hz5, coeff_vt_vec0, res_hz6, coeff_vt_vec1, + res_hz7, coeff_vt_vec0, res_vt4, res_vt5, res_vt6, res_vt7); + ADD2(res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt1); + ADD2(res_vt4, res_vt5, res_vt6, res_vt7, res_vt2, res_vt3); + SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); + SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); + PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, res0, res1); + AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); + ST4x8_UB(res0, res1, dst, stride); +} + +static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, @@ -1688,30 +1645,30 @@ static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, int32_t height) { if (2 == height) { - avc_chroma_hv_and_aver_dst_4x2_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); - } else { - avc_chroma_hv_and_aver_dst_4x4mul_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1, height); + avc_chroma_hv_and_aver_dst_4x2_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); + } else if (4 == height) { + avc_chroma_hv_and_aver_dst_4x4_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); + } else if (8 == height) { + avc_chroma_hv_and_aver_dst_4x8_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } } -static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coef_hor0, - uint32_t coef_hor1, - uint32_t coef_ver0, - uint32_t coef_ver1, - int32_t height) +static void avc_chroma_hv_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) { - uint32_t row; + uint64_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4, out0, out1; v8u16 res_hz0, res_hz1, res_hz2; v8u16 res_hz3, res_hz4; v8u16 res_vt0, res_vt1, res_vt2, res_vt3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0 = { 0 }, dst1 = { 0 }; v16i8 mask; v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); @@ -1722,197 +1679,226 @@ static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[32]); src0 = LD_UB(src); - src += src_stride; - + src += stride; src0 = (v16u8) __msa_vshf_b(mask, (v16i8) src0, (v16i8) src0); res_hz0 = __msa_dotp_u_h(src0, coeff_hz_vec); + LD_UB4(src, stride, src1, src2, src3, src4); + src += (4 * stride); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + VSHF_B2_UB(src1, src1, src2, src2, mask, mask, src1, src2); + VSHF_B2_UB(src3, src3, src4, src4, mask, mask, src3, src4); + DOTP_UB4_UH(src1, src2, src3, src4, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz1, res_hz2, res_hz3, res_hz4); + MUL4(res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec0, res_hz3, coeff_vt_vec0, + res_hz4, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + res_vt0 += (res_hz0 * coeff_vt_vec1); + res_vt1 += (res_hz1 * coeff_vt_vec1); + res_vt2 += (res_hz2 * coeff_vt_vec1); + res_vt3 += (res_hz3 * coeff_vt_vec1); + SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); + SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); + PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST8x4_UB(out0, out1, dst, stride); +} - for (row = (height >> 2); row--;) { - LD_UB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); +static void avc_chroma_hv_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) +{ + uint64_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v8u16 res_hz0, res_hz1, res_hz2, res_hz3, res_hz4; + v8u16 res_hz5, res_hz6, res_hz7, res_hz8; + v8u16 res_vt0, res_vt1, res_vt2, res_vt3; + v8u16 res_vt4, res_vt5, res_vt6, res_vt7; + v16i8 mask; + v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); + v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); + v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); + v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); + v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - VSHF_B2_UB(src1, src1, src2, src2, mask, mask, src1, src2); - VSHF_B2_UB(src3, src3, src4, src4, mask, mask, src3, src4); - DOTP_UB4_UH(src1, src2, src3, src4, coeff_hz_vec, coeff_hz_vec, - coeff_hz_vec, coeff_hz_vec, res_hz1, res_hz2, res_hz3, - res_hz4); - MUL4(res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec0, res_hz3, - coeff_vt_vec0, res_hz4, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, - res_vt3); + mask = LD_SB(&chroma_mask_arr[32]); - res_vt0 += (res_hz0 * coeff_vt_vec1); - res_vt1 += (res_hz1 * coeff_vt_vec1); - res_vt2 += (res_hz2 * coeff_vt_vec1); - res_vt3 += (res_hz3 * coeff_vt_vec1); + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + src0 = (v16u8) __msa_vshf_b(mask, (v16i8) src0, (v16i8) src0); + VSHF_B2_UB(src1, src1, src2, src2, mask, mask, src1, src2); + VSHF_B2_UB(src3, src3, src4, src4, mask, mask, src3, src4); + VSHF_B2_UB(src5, src5, src6, src6, mask, mask, src5, src6); + VSHF_B2_UB(src7, src7, src8, src8, mask, mask, src7, src8); + res_hz0 = __msa_dotp_u_h(src0, coeff_hz_vec); + DOTP_UB4_UH(src1, src2, src3, src4, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz1, res_hz2, res_hz3, + res_hz4); + DOTP_UB4_UH(src5, src6, src7, src8, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz5, res_hz6, res_hz7, res_hz8); + MUL4(res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec0, res_hz3, + coeff_vt_vec0, res_hz4, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, + res_vt3); + MUL4(res_hz5, coeff_vt_vec0, res_hz6, coeff_vt_vec0, res_hz7, + coeff_vt_vec0, res_hz8, coeff_vt_vec0, res_vt4, res_vt5, res_vt6, + res_vt7); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + res_vt0 += (res_hz0 * coeff_vt_vec1); + res_vt1 += (res_hz1 * coeff_vt_vec1); + res_vt2 += (res_hz2 * coeff_vt_vec1); + res_vt3 += (res_hz3 * coeff_vt_vec1); + res_vt4 += (res_hz4 * coeff_vt_vec1); + res_vt5 += (res_hz5 * coeff_vt_vec1); + res_vt6 += (res_hz6 * coeff_vt_vec1); + res_vt7 += (res_hz7 * coeff_vt_vec1); + SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); + SRARI_H4_UH(res_vt4, res_vt5, res_vt6, res_vt7, 6); + SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); + SAT_UH4_UH(res_vt4, res_vt5, res_vt6, res_vt7, 7); + PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); + PCKEV_B2_UB(res_vt5, res_vt4, res_vt7, res_vt6, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} - SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); - SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); - - PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - - res_hz0 = res_hz4; +static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1, + int32_t height) +{ + if (4 == height) { + avc_chroma_hv_and_aver_dst_8x4_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); + } else if (8 == height) { + avc_chroma_hv_and_aver_dst_8x8_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } } -static void copy_width8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void copy_width4_msa(uint8_t *src, uint8_t *dst, int32_t stride, int32_t height) { - int32_t cnt; - uint64_t out0, out1, out2, out3, out4, out5, out6, out7; - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + uint32_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; - if (0 == height % 12) { - for (cnt = (height / 12); cnt--;) { - LD_UB8(src, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * src_stride); - - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - out4 = __msa_copy_u_d((v2i64) src4, 0); - out5 = __msa_copy_u_d((v2i64) src5, 0); - out6 = __msa_copy_u_d((v2i64) src6, 0); - out7 = __msa_copy_u_d((v2i64) src7, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - SD4(out4, out5, out6, out7, dst, dst_stride); - dst += (4 * dst_stride); - - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == height % 8) { - for (cnt = height >> 3; cnt--;) { - LD_UB8(src, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * src_stride); - - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - out4 = __msa_copy_u_d((v2i64) src4, 0); - out5 = __msa_copy_u_d((v2i64) src5, 0); - out6 = __msa_copy_u_d((v2i64) src6, 0); - out7 = __msa_copy_u_d((v2i64) src7, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - SD4(out4, out5, out6, out7, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == height % 4) { - for (cnt = (height / 4); cnt--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == height % 2) { - for (cnt = (height / 2); cnt--;) { - LD_UB2(src, src_stride, src0, src1); - src += (2 * src_stride); - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - - SD(out0, dst); - dst += dst_stride; - SD(out1, dst); - dst += dst_stride; - } + if (8 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + LW4(src, stride, tp4, tp5, tp6, tp7); + SW4(tp0, tp1, tp2, tp3, dst, stride); + dst += 4 * stride; + SW4(tp4, tp5, tp6, tp7, dst, stride); + } else if (4 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + SW4(tp0, tp1, tp2, tp3, dst, stride); + } else if (2 == height) { + LW2(src, stride, tp0, tp1); + SW(tp0, dst); + dst += stride; + SW(tp1, dst); } } -static void avg_width4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) +static void copy_width8_msa(uint8_t *src, uint8_t *dst, int32_t stride, + int32_t height) { - int32_t cnt; - uint32_t out0, out1, out2, out3; - v16u8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; + uint64_t src0, src1, src2, src3, src4, src5, src6, src7; - if (0 == (height % 4)) { - for (cnt = (height / 4); cnt--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, - dst0, dst1, dst2, dst3); - - out0 = __msa_copy_u_w((v4i32) dst0, 0); - out1 = __msa_copy_u_w((v4i32) dst1, 0); - out2 = __msa_copy_u_w((v4i32) dst2, 0); - out3 = __msa_copy_u_w((v4i32) dst3, 0); - SW4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == (height % 2)) { - for (cnt = (height / 2); cnt--;) { - LD_UB2(src, src_stride, src0, src1); - src += (2 * src_stride); - - LD_UB2(dst, dst_stride, dst0, dst1); - - AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); - - out0 = __msa_copy_u_w((v4i32) dst0, 0); - out1 = __msa_copy_u_w((v4i32) dst1, 0); - SW(out0, dst); - dst += dst_stride; - SW(out1, dst); - dst += dst_stride; - } + if (8 == height) { + LD4(src, stride, src0, src1, src2, src3); + src += 4 * stride; + LD4(src, stride, src4, src5, src6, src7); + SD4(src0, src1, src2, src3, dst, stride); + dst += 4 * stride; + SD4(src4, src5, src6, src7, dst, stride); + } else if (4 == height) { + LD4(src, stride, src0, src1, src2, src3); + SD4(src0, src1, src2, src3, dst, stride); } } -static void avg_width8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avg_width4_msa(uint8_t *src, uint8_t *dst, int32_t stride, int32_t height) { - int32_t cnt; - uint64_t out0, out1, out2, out3; - v16u8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0 = { 0 }, src1 = { 0 }, dst0 = { 0 }, dst1 = { 0 }; - for (cnt = (height / 4); cnt--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); + if (8 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); + LW4(src, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, src1); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); + ST4x8_UB(dst0, dst1, dst, stride); + } else if (4 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + dst0 = __msa_aver_u_b(src0, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + } else if (2 == height) { + LW2(src, stride, tp0, tp1); + INSERT_W2_UB(tp0, tp1, src0); + LW2(dst, stride, tp0, tp1); + INSERT_W2_UB(tp0, tp1, dst0); + dst0 = __msa_aver_u_b(src0, dst0); + ST4x2_UB(dst0, dst, stride); + } +} - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, - dst0, dst1, dst2, dst3); +static void avg_width8_msa(uint8_t *src, uint8_t *dst, int32_t stride, + int32_t height) +{ + uint64_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; + v16u8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; - out0 = __msa_copy_u_d((v2i64) dst0, 0); - out1 = __msa_copy_u_d((v2i64) dst1, 0); - out2 = __msa_copy_u_d((v2i64) dst2, 0); - out3 = __msa_copy_u_d((v2i64) dst3, 0); - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); + if (8 == height) { + LD4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + LD4(src, stride, tp4, tp5, tp6, tp7); + INSERT_D2_UB(tp0, tp1, src0); + INSERT_D2_UB(tp2, tp3, src1); + INSERT_D2_UB(tp4, tp5, src2); + INSERT_D2_UB(tp6, tp7, src3); + LD4(dst, stride, tp0, tp1, tp2, tp3); + LD4(dst + 4 * stride, stride, tp4, tp5, tp6, tp7); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + INSERT_D2_UB(tp4, tp5, dst2); + INSERT_D2_UB(tp6, tp7, dst3); + AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + } else if (4 == height) { + LD4(src, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, src0); + INSERT_D2_UB(tp2, tp3, src1); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } } @@ -1928,15 +1914,13 @@ void ff_put_h264_chroma_mc8_msa(uint8_t *dst, uint8_t *src, } else if (y) { avc_chroma_vt_8w_msa(src, dst, stride, y, (8 - y), height); } else { - copy_width8_msa(src, stride, dst, stride, height); + copy_width8_msa(src, dst, stride, height); } } void ff_put_h264_chroma_mc4_msa(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, int x, int y) { - int32_t cnt; - av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); if (x && y) { @@ -1946,12 +1930,7 @@ void ff_put_h264_chroma_mc4_msa(uint8_t *dst, uint8_t *src, } else if (y) { avc_chroma_vt_4w_msa(src, dst, stride, y, (8 - y), height); } else { - for (cnt = height; cnt--;) { - *((uint32_t *) dst) = *((uint32_t *) src); - - src += stride; - dst += stride; - } + copy_width4_msa(src, dst, stride, height); } } @@ -1985,17 +1964,14 @@ void ff_avg_h264_chroma_mc8_msa(uint8_t *dst, uint8_t *src, if (x && y) { - avc_chroma_hv_and_aver_dst_8w_msa(src, stride, dst, - stride, x, (8 - x), y, + avc_chroma_hv_and_aver_dst_8w_msa(src, dst, stride, x, (8 - x), y, (8 - y), height); } else if (x) { - avc_chroma_hz_and_aver_dst_8w_msa(src, stride, dst, - stride, x, (8 - x), height); + avc_chroma_hz_and_aver_dst_8w_msa(src, dst, stride, x, (8 - x), height); } else if (y) { - avc_chroma_vt_and_aver_dst_8w_msa(src, stride, dst, - stride, y, (8 - y), height); + avc_chroma_vt_and_aver_dst_8w_msa(src, dst, stride, y, (8 - y), height); } else { - avg_width8_msa(src, stride, dst, stride, height); + avg_width8_msa(src, dst, stride, height); } } @@ -2005,17 +1981,14 @@ void ff_avg_h264_chroma_mc4_msa(uint8_t *dst, uint8_t *src, av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); if (x && y) { - avc_chroma_hv_and_aver_dst_4w_msa(src, stride, dst, - stride, x, (8 - x), y, + avc_chroma_hv_and_aver_dst_4w_msa(src, dst, stride, x, (8 - x), y, (8 - y), height); } else if (x) { - avc_chroma_hz_and_aver_dst_4w_msa(src, stride, dst, - stride, x, (8 - x), height); + avc_chroma_hz_and_aver_dst_4w_msa(src, dst, stride, x, (8 - x), height); } else if (y) { - avc_chroma_vt_and_aver_dst_4w_msa(src, stride, dst, - stride, y, (8 - y), height); + avc_chroma_vt_and_aver_dst_4w_msa(src, dst, stride, y, (8 - y), height); } else { - avg_width4_msa(src, stride, dst, stride, height); + avg_width4_msa(src, dst, stride, height); } } @@ -2027,15 +2000,12 @@ void ff_avg_h264_chroma_mc2_msa(uint8_t *dst, uint8_t *src, av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); if (x && y) { - avc_chroma_hv_and_aver_dst_2w_msa(src, stride, dst, - stride, x, (8 - x), y, + avc_chroma_hv_and_aver_dst_2w_msa(src, dst, stride, x, (8 - x), y, (8 - y), height); } else if (x) { - avc_chroma_hz_and_aver_dst_2w_msa(src, stride, dst, - stride, x, (8 - x), height); + avc_chroma_hz_and_aver_dst_2w_msa(src, dst, stride, x, (8 - x), height); } else if (y) { - avc_chroma_vt_and_aver_dst_2w_msa(src, stride, dst, - stride, y, (8 - y), height); + avc_chroma_vt_and_aver_dst_2w_msa(src, dst, stride, y, (8 - y), height); } else { for (cnt = height; cnt--;) { dst[0] = (dst[0] + src[0] + 1) >> 1; diff --git a/libavcodec/mips/h264qpel_msa.c b/libavcodec/mips/h264qpel_msa.c index a22a4828c..9c779bdd4 100644 --- a/libavcodec/mips/h264qpel_msa.c +++ b/libavcodec/mips/h264qpel_msa.c @@ -21,31 +21,7 @@ #include "libavutil/mips/generic_macros_msa.h" #include "h264dsp_mips.h" -#define AVC_CALC_DPADD_H_6PIX_2COEFF_SH(in0, in1, in2, in3, in4, in5) \ -( { \ - v4i32 tmp0_m, tmp1_m; \ - v8i16 out0_m, out1_m, out2_m, out3_m; \ - v8i16 minus5h_m = __msa_ldi_h(-5); \ - v8i16 plus20h_m = __msa_ldi_h(20); \ - \ - ILVRL_H2_SW(in5, in0, tmp0_m, tmp1_m); \ - \ - tmp0_m = __msa_hadd_s_w((v8i16) tmp0_m, (v8i16) tmp0_m); \ - tmp1_m = __msa_hadd_s_w((v8i16) tmp1_m, (v8i16) tmp1_m); \ - \ - ILVRL_H2_SH(in1, in4, out0_m, out1_m); \ - DPADD_SH2_SW(out0_m, out1_m, minus5h_m, minus5h_m, tmp0_m, tmp1_m); \ - ILVRL_H2_SH(in2, in3, out2_m, out3_m); \ - DPADD_SH2_SW(out2_m, out3_m, plus20h_m, plus20h_m, tmp0_m, tmp1_m); \ - \ - SRARI_W2_SW(tmp0_m, tmp1_m, 10); \ - SAT_SW2_SW(tmp0_m, tmp1_m, 7); \ - out0_m = __msa_pckev_h((v8i16) tmp1_m, (v8i16) tmp0_m); \ - \ - out0_m; \ -} ) - -static const uint8_t luma_mask_arr[16 * 8] = { +static const uint8_t luma_mask_arr[16 * 6] __attribute__((aligned(0x40))) = { /* 8 width cases */ 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 6, 9, 7, 10, 8, 11, @@ -55,9 +31,6 @@ static const uint8_t luma_mask_arr[16 * 8] = { 0, 5, 1, 6, 2, 7, 3, 8, 16, 21, 17, 22, 18, 23, 19, 24, 1, 4, 2, 5, 3, 6, 4, 7, 17, 20, 18, 21, 19, 22, 20, 23, 2, 3, 3, 4, 4, 5, 5, 6, 18, 19, 19, 20, 20, 21, 21, 22, - - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26 }; #define AVC_CALC_DPADD_B_6PIX_2COEFF_SH(vec0, vec1, vec2, vec3, vec4, vec5, \ @@ -75,60 +48,6 @@ static const uint8_t luma_mask_arr[16 * 8] = { DPADD_SB2_SH(tmp0_m, tmp1_m, plus20b_m, plus20b_m, out1, out2); \ } -#define AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(vec0, vec1, vec2, vec3, vec4, vec5) \ -( { \ - v8i16 tmp1_m; \ - v16i8 tmp0_m, tmp2_m; \ - v16i8 minus5b_m = __msa_ldi_b(-5); \ - v16i8 plus20b_m = __msa_ldi_b(20); \ - \ - tmp1_m = (v8i16) __msa_ilvr_b((v16i8) vec5, (v16i8) vec0); \ - tmp1_m = __msa_hadd_s_h((v16i8) tmp1_m, (v16i8) tmp1_m); \ - \ - ILVR_B2_SB(vec4, vec1, vec3, vec2, tmp0_m, tmp2_m); \ - DPADD_SB2_SH(tmp0_m, tmp2_m, minus5b_m, plus20b_m, tmp1_m, tmp1_m); \ - \ - tmp1_m; \ -} ) - -#define AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(vec0, vec1, vec2, vec3, vec4, vec5) \ -( { \ - v4i32 tmp1_m; \ - v8i16 tmp2_m, tmp3_m; \ - v8i16 minus5h_m = __msa_ldi_h(-5); \ - v8i16 plus20h_m = __msa_ldi_h(20); \ - \ - tmp1_m = (v4i32) __msa_ilvr_h((v8i16) vec5, (v8i16) vec0); \ - tmp1_m = __msa_hadd_s_w((v8i16) tmp1_m, (v8i16) tmp1_m); \ - \ - ILVR_H2_SH(vec1, vec4, vec2, vec3, tmp2_m, tmp3_m); \ - DPADD_SH2_SW(tmp2_m, tmp3_m, minus5h_m, plus20h_m, tmp1_m, tmp1_m); \ - \ - tmp1_m = __msa_srari_w(tmp1_m, 10); \ - tmp1_m = __msa_sat_s_w(tmp1_m, 7); \ - \ - tmp2_m = __msa_pckev_h((v8i16) tmp1_m, (v8i16) tmp1_m); \ - \ - tmp2_m; \ -} ) - -#define AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, \ - mask0, mask1, mask2) \ -( { \ - v8i16 hz_out_m; \ - v16i8 vec0_m, vec1_m, vec2_m; \ - v16i8 minus5b_m = __msa_ldi_b(-5); \ - v16i8 plus20b_m = __msa_ldi_b(20); \ - \ - vec0_m = __msa_vshf_b((v16i8) mask0, (v16i8) src1, (v16i8) src0); \ - hz_out_m = __msa_hadd_s_h(vec0_m, vec0_m); \ - \ - VSHF_B2_SB(src0, src1, src0, src1, mask1, mask2, vec1_m, vec2_m); \ - DPADD_SB2_SH(vec1_m, vec2_m, minus5b_m, plus20b_m, hz_out_m, hz_out_m); \ - \ - hz_out_m; \ -} ) - #define AVC_HORZ_FILTER_SH(in0, in1, mask0, mask1, mask2) \ ( { \ v8i16 out0_m; \ @@ -171,258 +90,27 @@ static const uint8_t luma_mask_arr[16 * 8] = { out0_m; \ } ) -static void avc_luma_mid_4w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) +static void avc_luma_hv_qrt_4x4_msa(const uint8_t *src_x, const uint8_t *src_y, + uint8_t *dst, int32_t stride) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 dst0, dst1, dst2, dst3; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out2 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); - - PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); - - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - XORI_B4_128_SB(src0, src1, src2, src3); - - hz_out5 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, - mask2); - hz_out7 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, - mask2); - - PCKOD_D2_SH(hz_out5, hz_out5, hz_out7, hz_out7, hz_out6, hz_out8); - - dst0 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - dst1 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - dst2 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - dst3 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - - PCKEV_B2_SB(dst1, dst0, dst3, dst2, src0, src1); - XORI_B2_128_SB(src0, src1); - - ST4x4_UB(src0, src1, 0, 2, 0, 2, dst, dst_stride); - - dst += (4 * dst_stride); - - hz_out0 = hz_out4; - hz_out1 = hz_out5; - hz_out2 = hz_out6; - hz_out3 = hz_out7; - hz_out4 = hz_out8; - } -} - -static void avc_luma_mid_8w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) -{ - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 dst0, dst1, dst2, dst3; - v16u8 out0, out1; - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - src += (5 * src_stride); - - hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - - hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - dst0 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - dst1 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - dst2 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - dst3 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, dst_stride); - - dst += (4 * dst_stride); - hz_out3 = hz_out7; - hz_out1 = hz_out5; - hz_out5 = hz_out4; - hz_out4 = hz_out8; - hz_out2 = hz_out6; - hz_out0 = hz_out5; - } -} - -static void avc_luma_mid_16w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_mid_8w_msa(src, src_stride, dst, dst_stride, height); - src += 8; - dst += 8; - } -} - -static void avc_luma_midh_qrt_4w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height, uint8_t horiz_offset) -{ - uint32_t row; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v8i16 vt_res0, vt_res1, vt_res2, vt_res3; - v4i32 hz_res0, hz_res1; - v8i16 dst0, dst1; - v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5; - v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; - v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; - v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; - v8i16 minus5h = __msa_ldi_h(-5); - v8i16 plus20h = __msa_ldi_h(20); - v8i16 zeros = { 0 }; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; v16u8 out; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, src_vt7, src_vt8; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt10_r, src_vt32_r, src_vt54_r, src_vt76_r; + v16i8 mask0, mask1, mask2, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, vt_out0, vt_out1, out0, out1; - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - - for (row = (height >> 1); row--;) { - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - - XORI_B2_128_SB(src5, src6); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, - vt_res0, vt_res1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, - vt_res2, vt_res3); - VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, - mask0, mask1, mask2, shf_vec0, shf_vec1, shf_vec2); - VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, - mask0, mask1, mask2, shf_vec3, shf_vec4, shf_vec5); - hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); - DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); - hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); - DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); - - SRARI_W2_SW(hz_res0, hz_res1, 10); - SAT_SW2_SW(hz_res0, hz_res1, 7); - - dst0 = __msa_srari_h(shf_vec2, 5); - dst1 = __msa_srari_h(shf_vec5, 5); - - SAT_SH2_SH(dst0, dst1, 7); - - if (horiz_offset) { - dst0 = __msa_ilvod_h(zeros, dst0); - dst1 = __msa_ilvod_h(zeros, dst1); - } else { - ILVEV_H2_SH(dst0, zeros, dst1, zeros, dst0, dst1); - } - - hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); - hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); - dst0 = __msa_pckev_h((v8i16) hz_res1, (v8i16) hz_res0); - - out = PCKEV_XORI128_UB(dst0, dst0); - ST4x2_UB(out, dst, dst_stride); - - dst += (2 * dst_stride); - - src0 = src2; - src1 = src3; - src2 = src4; - src3 = src5; - src4 = src6; - } -} - -static void avc_luma_midh_qrt_8w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height, uint8_t horiz_offset) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_midh_qrt_4w_msa(src, src_stride, dst, dst_stride, height, - horiz_offset); - - src += 4; - dst += 4; - } -} - -static void avc_luma_midh_qrt_16w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height, uint8_t horiz_offset) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 4; multiple8_cnt--;) { - avc_luma_midh_qrt_4w_msa(src, src_stride, dst, dst_stride, height, - horiz_offset); - - src += 4; - dst += 4; - } -} - -static void avc_luma_hv_qrt_4w_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride, int32_t height) -{ - uint32_t loop_cnt; - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4; - v16i8 src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, vert_out0, vert_out1; - v8i16 out0, out1; - v16u8 out; + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); src_vt0 = (v16i8) __msa_insve_w((v4i32) src_vt0, 1, (v4i32) src_vt1); src_vt1 = (v16i8) __msa_insve_w((v4i32) src_vt1, 1, (v4i32) src_vt2); @@ -431,1329 +119,15 @@ static void avc_luma_hv_qrt_4w_msa(const uint8_t *src_x, const uint8_t *src_y, XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - src_x += (4 * src_stride); - - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz0, - src_hz1, mask0, - mask1, mask2); - hz_out1 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz2, - src_hz3, mask0, - mask1, mask2); - - SRARI_H2_SH(hz_out0, hz_out1, 5); - SAT_SH2_SH(hz_out0, hz_out1, 7); - - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - src_y += (4 * src_stride); - - src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); - src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); - src_vt6 = (v16i8) __msa_insve_w((v4i32) src_vt6, 1, (v4i32) src_vt7); - src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); - - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); - - /* filter calc */ - vert_out0 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt0, src_vt1, - src_vt2, src_vt3, - src_vt4, src_vt5); - vert_out1 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt2, src_vt3, - src_vt4, src_vt5, - src_vt6, src_vt7); - - SRARI_H2_SH(vert_out0, vert_out1, 5); - SAT_SH2_SH(vert_out0, vert_out1, 7); - - out0 = __msa_srari_h((hz_out0 + vert_out0), 1); - out1 = __msa_srari_h((hz_out1 + vert_out1), 1); - - SAT_SH2_SH(out0, out1, 7); - out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); - - src_vt3 = src_vt7; - src_vt1 = src_vt5; - src_vt0 = src_vt4; - src_vt4 = src_vt8; - src_vt2 = src_vt6; - } -} - -static void avc_luma_hv_qrt_8w_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride, int32_t height) -{ - uint32_t loop_cnt; - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4; - v16i8 src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 vert_out0, vert_out1, vert_out2, vert_out3; - v8i16 out0, out1, out2, out3; - v16u8 tmp0, tmp1; - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); - - src_vt0 = (v16i8) __msa_insve_d((v2i64) src_vt0, 1, (v2i64) src_vt1); - src_vt1 = (v16i8) __msa_insve_d((v2i64) src_vt1, 1, (v2i64) src_vt2); - src_vt2 = (v16i8) __msa_insve_d((v2i64) src_vt2, 1, (v2i64) src_vt3); - src_vt3 = (v16i8) __msa_insve_d((v2i64) src_vt3, 1, (v2i64) src_vt4); - - XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - src_x += (4 * src_stride); - - hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); - - SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); - SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); - - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - src_y += (4 * src_stride); - - src_vt4 = (v16i8) __msa_insve_d((v2i64) src_vt4, 1, (v2i64) src_vt5); - src_vt5 = (v16i8) __msa_insve_d((v2i64) src_vt5, 1, (v2i64) src_vt6); - src_vt6 = (v16i8) __msa_insve_d((v2i64) src_vt6, 1, (v2i64) src_vt7); - src_vt7 = (v16i8) __msa_insve_d((v2i64) src_vt7, 1, (v2i64) src_vt8); - - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); - - /* filter calc */ - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt0, src_vt1, src_vt2, src_vt3, - src_vt4, src_vt5, vert_out0, vert_out1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt2, src_vt3, src_vt4, src_vt5, - src_vt6, src_vt7, vert_out2, vert_out3); - - SRARI_H4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 5); - SAT_SH4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 7); - - out0 = __msa_srari_h((hz_out0 + vert_out0), 1); - out1 = __msa_srari_h((hz_out1 + vert_out1), 1); - out2 = __msa_srari_h((hz_out2 + vert_out2), 1); - out3 = __msa_srari_h((hz_out3 + vert_out3), 1); - - SAT_SH4_SH(out0, out1, out2, out3, 7); - tmp0 = PCKEV_XORI128_UB(out0, out1); - tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); - - dst += (4 * dst_stride); - src_vt3 = src_vt7; - src_vt1 = src_vt5; - src_vt5 = src_vt4; - src_vt4 = src_vt8; - src_vt2 = src_vt6; - src_vt0 = src_vt5; - } -} - -static void avc_luma_hv_qrt_16w_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride, int32_t height) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_hv_qrt_8w_msa(src_x, src_y, src_stride, dst, dst_stride, - height); - - src_x += 8; - src_y += 8; - dst += 8; - } -} - -static void avc_luma_hz_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - v16i8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3, res; - v8i16 res0, res1; - v16i8 mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB4(src, src_stride, src0, src1, src2, src3); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); - HADD_SB2_SH(vec0, vec1, res0, res1); - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); - DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); - DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); - SRARI_H2_SH(res0, res1, 5); - SAT_SH2_SH(res0, res1, 7); - res = PCKEV_XORI128_UB(res0, res1); - ILVR_W2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - - dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0); - res = __msa_aver_u_b(res, dst0); - - ST4x4_UB(res, res, 0, 1, 2, 3, dst, dst_stride); -} - -static void avc_luma_hz_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; - v8i16 res0, res1, res2, res3; - v16i8 mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); - HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); - DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, - res0, res1, res2, res3); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); - DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, - plus20b, res0, res1, res2, res3); - SRARI_H4_SH(res0, res1, res2, res3, 5); - SAT_SH4_SH(res0, res1, res2, res3, 7); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(res0, res1, res2, res3, dst0, dst1, - dst, dst_stride); - - dst += (4 * dst_stride); - } -} - -static void avc_luma_hz_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 dst0, dst1, dst2, dst3; - v16i8 mask0, mask1, mask2; - v8i16 res0, res1, res2, res3, res4, res5, res6, res7; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - for (loop_cnt = 4; loop_cnt--;) { - LD_SB2(src, 8, src0, src1); - src += src_stride; - LD_SB2(src, 8, src2, src3); - src += src_stride; - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec1, vec4); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec7, vec10); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec2, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec8, vec11); - HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); - DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, - minus5b, res0, res1, res2, res3); - DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, - plus20b, res0, res1, res2, res3); - LD_SB2(src, 8, src4, src5); - src += src_stride; - LD_SB2(src, 8, src6, src7); - src += src_stride; - XORI_B4_128_SB(src4, src5, src6, src7); - VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec3); - VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec6, vec9); - VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec1, vec4); - VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec7, vec10); - VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec2, vec5); - VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec8, vec11); - HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); - DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, - minus5b, res4, res5, res6, res7); - DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, - plus20b, res4, res5, res6, res7); - SRARI_H4_SH(res0, res1, res2, res3, 5); - SRARI_H4_SH(res4, res5, res6, res7, 5); - SAT_SH4_SH(res0, res1, res2, res3, 7); - SAT_SH4_SH(res4, res5, res6, res7, 7); - PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, - vec0, vec1, vec2, vec3); - XORI_B4_128_SB(vec0, vec1, vec2, vec3); - AVER_UB4_UB(vec0, dst0, vec1, dst1, vec2, dst2, vec3, dst3, - dst0, dst1, dst2, dst3); - ST_UB4(dst0, dst1, dst2, dst3, dst, dst_stride); - dst += (4 * dst_stride); - } -} - -static void avc_luma_hz_qrt_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t hor_offset) -{ - uint8_t slide; - v16i8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; - v16i8 mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 out0, out1; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - v16u8 res0, res1; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - - if (hor_offset) { - slide = 3; - } else { - slide = 2; - } - - LD_SB4(src, src_stride, src0, src1, src2, src3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); - HADD_SB2_SH(vec0, vec1, out0, out1); - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); - DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, out0, out1); - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); - DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, out0, out1); - SRARI_H2_SH(out0, out1, 5); - SAT_SH2_SH(out0, out1, 7); - - PCKEV_B2_UB(out0, out0, out1, out1, res0, res1); - - src0 = __msa_sld_b(src0, src0, slide); - src1 = __msa_sld_b(src1, src1, slide); - src2 = __msa_sld_b(src2, src2, slide); - src3 = __msa_sld_b(src3, src3, slide); - src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); - src1 = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); - res0 = (v16u8) __msa_aver_s_b((v16i8) res0, src0); - res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src1); - - XORI_B2_128_UB(res0, res1); - - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst1 = (v16u8) __msa_insve_w((v4i32) dst2, 1, (v4i32) dst3); - - AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); - - ST4x4_UB(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); -} - -static void avc_luma_hz_qrt_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t hor_offset) -{ - uint8_t slide; - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3; - v16i8 mask0, mask1, mask2; - v16u8 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v8i16 out0, out1, out2, out3; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - v16i8 res0, res1, res2, res3; - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - if (hor_offset) { - slide = 3; - } else { - slide = 2; - } - - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); - HADD_SB4_SH(vec0, vec1, vec2, vec3, out0, out1, out2, out3); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); - DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, - out0, out1, out2, out3); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); - DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, - plus20b, out0, out1, out2, out3); - - src0 = __msa_sld_b(src0, src0, slide); - src1 = __msa_sld_b(src1, src1, slide); - src2 = __msa_sld_b(src2, src2, slide); - src3 = __msa_sld_b(src3, src3, slide); - - SRARI_H4_SH(out0, out1, out2, out3, 5); - SAT_SH4_SH(out0, out1, out2, out3, 7); - - PCKEV_B4_SB(out0, out0, out1, out1, out2, out2, out3, out3, - res0, res1, res2, res3); - - res0 = __msa_aver_s_b(res0, src0); - res1 = __msa_aver_s_b(res1, src1); - res2 = __msa_aver_s_b(res2, src2); - res3 = __msa_aver_s_b(res3, src3); - - XORI_B4_128_SB(res0, res1, res2, res3); - AVER_ST8x4_UB(res0, dst0, res1, dst1, res2, dst2, res3, dst3, - dst, dst_stride); - - dst += (4 * dst_stride); - } -} - -static void avc_luma_hz_qrt_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t hor_offset) -{ - uint32_t loop_cnt; - v16i8 out0, out1; - v16i8 src0, src1, src2, src3; - v16i8 mask0, mask1, mask2, vshf; - v16u8 dst0, dst1; - v8i16 res0, res1, res2, res3; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - if (hor_offset) { - vshf = LD_SB(&luma_mask_arr[16 + 96]); - } else { - vshf = LD_SB(&luma_mask_arr[96]); - } - - for (loop_cnt = 8; loop_cnt--;) { - LD_SB2(src, 8, src0, src1); - src += src_stride; - LD_SB2(src, 8, src2, src3); - src += src_stride; - - LD_UB2(dst, dst_stride, dst0, dst1); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec1, vec4); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec7, vec10); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec2, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec8, vec11); - HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); - DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, - minus5b, res0, res1, res2, res3); - DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, - plus20b, res0, res1, res2, res3); - VSHF_B2_SB(src0, src1, src2, src3, vshf, vshf, src0, src2); - SRARI_H4_SH(res0, res1, res2, res3, 5); - SAT_SH4_SH(res0, res1, res2, res3, 7); - PCKEV_B2_SB(res1, res0, res3, res2, out0, out1); - - out0 = __msa_aver_s_b(out0, src0); - out1 = __msa_aver_s_b(out1, src2); - - XORI_B2_128_SB(out0, out1); - AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST_UB2(dst0, dst1, dst, dst_stride); - dst += (2 * dst_stride); - } -} - -static void avc_luma_vt_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src2110, src4332, src6554, src8776; - v8i16 out10, out32; - v16i8 filt0, filt1, filt2; - v16u8 res; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); - XORI_B2_128_SB(src2110, src4332); - LD_SB4(src, src_stride, src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); - XORI_B2_128_SB(src6554, src8776); - out10 = DPADD_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); - out32 = DPADD_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); - SRARI_H2_SH(out10, out32, 5); - SAT_SH2_SH(out10, out32, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - res = PCKEV_XORI128_UB(out10, out32); - - ILVR_W2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - - dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0); - dst0 = __msa_aver_u_b(res, dst0); - - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); -} - -static void avc_luma_vt_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10; - v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 out0, out1, out2, out3; - v16i8 filt0, filt1, filt2; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src7, src8, src9, src10); - src += (4 * src_stride); - - XORI_B4_128_SB(src7, src8, src9, src10); - ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, - src76_r, src87_r, src98_r, src109_r); - out0 = DPADD_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); - out1 = DPADD_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); - out2 = DPADD_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); - out3 = DPADD_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); - SRARI_H4_SH(out0, out1, out2, out3, 5); - SAT_SH4_SH(out0, out1, out2, out3, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(out0, out1, out2, out3, dst0, dst1, - dst, dst_stride); - dst += (4 * dst_stride); - - src10_r = src76_r; - src32_r = src98_r; - src21_r = src87_r; - src43_r = src109_r; - src4 = src10; - } -} - -static void avc_luma_vt_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; - v16i8 src65_l, src87_l; - v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; - v16i8 filt0, filt1, filt2; - v16u8 res0, res1, res2, res3; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_l, src21_l, src32_l, src43_l); - - for (loop_cnt = 4; loop_cnt--;) { - LD_SB4(src, src_stride, src5, src6, src7, src8); - src += (4 * src_stride); - - XORI_B4_128_SB(src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_l, src65_l, src76_l, src87_l); - out0_r = DPADD_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); - out1_r = DPADD_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); - out2_r = DPADD_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); - out3_r = DPADD_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); - out0_l = DPADD_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); - out1_l = DPADD_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); - out2_l = DPADD_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); - out3_l = DPADD_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); - SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); - SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); - SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, - out3_r, res0, res1, res2, res3); - XORI_B4_128_UB(res0, res1, res2, res3); - AVER_UB4_UB(res0, dst0, res1, dst1, res2, dst2, res3, dst3, - res0, res1, res2, res3); - ST_UB4(res0, res1, res2, res3, dst, dst_stride); - dst += (4 * dst_stride); - - src10_r = src54_r; - src32_r = src76_r; - src21_r = src65_r; - src43_r = src87_r; - src10_l = src54_l; - src32_l = src76_l; - src21_l = src65_l; - src43_l = src87_l; - src4 = src8; - } -} - -static void avc_luma_vt_qrt_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t ver_offset) -{ - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src2110, src4332, src6554, src8776; - v8i16 out10, out32; - v16i8 filt0, filt1, filt2; - v16u8 res; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); - XORI_B2_128_SB(src2110, src4332); - LD_SB4(src, src_stride, src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); - XORI_B2_128_SB(src6554, src8776); - out10 = DPADD_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); - out32 = DPADD_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); - SRARI_H2_SH(out10, out32, 5); - SAT_SH2_SH(out10, out32, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - res = PCKEV_XORI128_UB(out10, out32); - - if (ver_offset) { - src32_r = (v16i8) __msa_insve_w((v4i32) src3, 1, (v4i32) src4); - src54_r = (v16i8) __msa_insve_w((v4i32) src5, 1, (v4i32) src6); - } else { - src32_r = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); - src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); - } - - src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); - res = __msa_aver_u_b(res, (v16u8) src32_r); - - ILVR_W2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - - dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0); - dst0 = __msa_aver_u_b(res, dst0); - - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); -} - -static void avc_luma_vt_qrt_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t ver_offset) -{ - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10; - v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 out0_r, out1_r, out2_r, out3_r; - v16i8 res0, res1; - v16u8 vec0, vec1; - v16i8 filt0, filt1, filt2; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src7, src8, src9, src10); - src += (4 * src_stride); - - XORI_B4_128_SB(src7, src8, src9, src10); - ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, - src76_r, src87_r, src98_r, src109_r); - out0_r = DPADD_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); - out1_r = DPADD_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); - out2_r = DPADD_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); - out3_r = DPADD_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); - SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); - PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, res0, res1); - - if (ver_offset) { - PCKEV_D2_SB(src4, src3, src8, src7, src10_r, src32_r); - } else { - PCKEV_D2_SB(src3, src2, src7, src4, src10_r, src32_r); - } - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - - vec0 = (v16u8) __msa_aver_s_b(res0, src10_r); - vec1 = (v16u8) __msa_aver_s_b(res1, src32_r); - - XORI_B2_128_UB(vec0, vec1); - AVER_UB2_UB(vec0, dst0, vec1, dst1, vec0, vec1); - ST8x4_UB(vec0, vec1, dst, dst_stride); - dst += (4 * dst_stride); - - src10_r = src76_r; - src32_r = src98_r; - src21_r = src87_r; - src43_r = src109_r; - src2 = src8; - src3 = src9; - src4 = src10; - } -} - -static void avc_luma_vt_qrt_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t ver_offset) -{ - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; - v16i8 src65_l, src87_l; - v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; - v16i8 out0, out1, out2, out3; - v16i8 filt0, filt1, filt2; - v16u8 res0, res1, res2, res3; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_l, src21_l, src32_l, src43_l); - - for (loop_cnt = 4; loop_cnt--;) { - LD_SB4(src, src_stride, src5, src6, src7, src8); - src += (4 * src_stride); - - XORI_B4_128_SB(src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_l, src65_l, src76_l, src87_l); - out0_r = DPADD_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); - out1_r = DPADD_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); - out2_r = DPADD_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); - out3_r = DPADD_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); - out0_l = DPADD_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); - out1_l = DPADD_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); - out2_l = DPADD_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); - out3_l = DPADD_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); - SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); - SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); - SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); - PCKEV_B4_SB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, - out3_r, out0, out1, out2, out3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - if (ver_offset) { - res0 = (v16u8) __msa_aver_s_b(out0, src3); - res1 = (v16u8) __msa_aver_s_b(out1, src4); - res2 = (v16u8) __msa_aver_s_b(out2, src5); - res3 = (v16u8) __msa_aver_s_b(out3, src6); - } else { - res0 = (v16u8) __msa_aver_s_b(out0, src2); - res1 = (v16u8) __msa_aver_s_b(out1, src3); - res2 = (v16u8) __msa_aver_s_b(out2, src4); - res3 = (v16u8) __msa_aver_s_b(out3, src5); - } - - XORI_B4_128_UB(res0, res1, res2, res3); - AVER_UB4_UB(res0, dst0, res1, dst1, res2, dst2, res3, dst3, - dst0, dst1, dst2, dst3); - ST_UB4(dst0, dst1, dst2, dst3, dst, dst_stride); - dst += (4 * dst_stride); - - src10_r = src54_r; - src32_r = src76_r; - src21_r = src65_r; - src43_r = src87_r; - src10_l = src54_l; - src32_l = src76_l; - src21_l = src65_l; - src43_l = src87_l; - src2 = src6; - src3 = src7; - src4 = src8; - } -} - -static void avc_luma_mid_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 res0, res1, res2, res3; - v16u8 dst0, dst1, dst2, dst3; - v16u8 tmp0, tmp1, tmp2, tmp3; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out2 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); - - PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); - - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - - hz_out5 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out7 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); - - PCKOD_D2_SH(hz_out5, hz_out5, hz_out7, hz_out7, hz_out6, hz_out8); - - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res1 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - res3 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - tmp0 = PCKEV_XORI128_UB(res0, res1); - tmp1 = PCKEV_XORI128_UB(res2, res3); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, tmp2, tmp3); - AVER_UB2_UB(tmp0, tmp2, tmp1, tmp3, tmp0, tmp1); - - ST4x4_UB(tmp0, tmp1, 0, 2, 0, 2, dst, dst_stride); -} - -static void avc_luma_mid_and_aver_dst_8w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) -{ - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v16u8 dst0, dst1, dst2, dst3; - v8i16 res0, res1, res2, res3; - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - src += (5 * src_stride); - - hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - - hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res1 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - res3 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(res0, res1, res2, res3, dst0, dst1, - dst, dst_stride); - - dst += (4 * dst_stride); - hz_out3 = hz_out7; - hz_out1 = hz_out5; - hz_out5 = hz_out4; - hz_out4 = hz_out8; - hz_out2 = hz_out6; - hz_out0 = hz_out5; - } -} - -static void avc_luma_mid_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride) -{ - avc_luma_mid_and_aver_dst_8w_msa(src, src_stride, dst, dst_stride, 16); - avc_luma_mid_and_aver_dst_8w_msa(src + 8, src_stride, dst + 8, dst_stride, - 16); -} - -static void avc_luma_midh_qrt_and_aver_dst_4w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t horiz_offset) -{ - uint32_t row; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v16u8 dst0, dst1, res; - v8i16 vt_res0, vt_res1, vt_res2, vt_res3; - v4i32 hz_res0, hz_res1; - v8i16 res0, res1; - v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5; - v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; - v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; - v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; - v8i16 minus5h = __msa_ldi_h(-5); - v8i16 plus20h = __msa_ldi_h(20); - v8i16 zeros = { 0 }; - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - - for (row = (height >> 1); row--;) { - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - - XORI_B2_128_SB(src5, src6); - LD_UB2(dst, dst_stride, dst0, dst1); - - dst0 = (v16u8) __msa_ilvr_w((v4i32) dst1, (v4i32) dst0); - - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, - vt_res0, vt_res1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, - vt_res2, vt_res3); - VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, - mask0, mask1, mask2, shf_vec0, shf_vec1, shf_vec2); - VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, - mask0, mask1, mask2, shf_vec3, shf_vec4, shf_vec5); - - hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); - DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); - - hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); - DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); - - SRARI_W2_SW(hz_res0, hz_res1, 10); - SAT_SW2_SW(hz_res0, hz_res1, 7); - - res0 = __msa_srari_h(shf_vec2, 5); - res1 = __msa_srari_h(shf_vec5, 5); - - SAT_SH2_SH(res0, res1, 7); - - if (horiz_offset) { - res0 = __msa_ilvod_h(zeros, res0); - res1 = __msa_ilvod_h(zeros, res1); - } else { - ILVEV_H2_SH(res0, zeros, res1, zeros, res0, res1); - } - hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) res0); - hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) res1); - res0 = __msa_pckev_h((v8i16) hz_res1, (v8i16) hz_res0); - - res = PCKEV_XORI128_UB(res0, res0); - - dst0 = __msa_aver_u_b(res, dst0); - - ST4x2_UB(dst0, dst, dst_stride); - dst += (2 * dst_stride); - - src0 = src2; - src1 = src3; - src2 = src4; - src3 = src5; - src4 = src6; - } -} - -static void avc_luma_midh_qrt_and_aver_dst_8w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t horiz_offset) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_midh_qrt_and_aver_dst_4w_msa(src, src_stride, dst, dst_stride, - height, horiz_offset); - - src += 4; - dst += 4; - } -} - -static void avc_luma_midh_qrt_and_aver_dst_16w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t horiz_offset) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 4; multiple8_cnt--;) { - avc_luma_midh_qrt_and_aver_dst_4w_msa(src, src_stride, dst, dst_stride, - height, horiz_offset); - - src += 4; - dst += 4; - } -} - -static void avc_luma_midv_qrt_and_aver_dst_4w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t ver_offset) -{ - int32_t loop_cnt; - int32_t out0, out1; - v16i8 src0, src1, src2, src3, src4; - v16u8 dst0, dst1; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6; - v8i16 res0, res1, res2, res3; - v16u8 vec0, vec1; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out2 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); - - PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); - - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src, src_stride, src0, src1); - src += (2 * src_stride); - - XORI_B2_128_SB(src0, src1); - LD_UB2(dst, dst_stride, dst0, dst1); - hz_out5 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, - mask2); - hz_out6 = (v8i16) __msa_pckod_d((v2i64) hz_out5, (v2i64) hz_out5); - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - - if (ver_offset) { - res1 = __msa_srari_h(hz_out3, 5); - res3 = __msa_srari_h(hz_out4, 5); - } else { - res1 = __msa_srari_h(hz_out2, 5); - res3 = __msa_srari_h(hz_out3, 5); - } - - SAT_SH2_SH(res1, res3, 7); - - res0 = __msa_aver_s_h(res0, res1); - res1 = __msa_aver_s_h(res2, res3); - - vec0 = PCKEV_XORI128_UB(res0, res0); - vec1 = PCKEV_XORI128_UB(res1, res1); - - AVER_UB2_UB(vec0, dst0, vec1, dst1, dst0, dst1); - - out0 = __msa_copy_u_w((v4i32) dst0, 0); - out1 = __msa_copy_u_w((v4i32) dst1, 0); - SW(out0, dst); - dst += dst_stride; - SW(out1, dst); - dst += dst_stride; - - hz_out0 = hz_out2; - hz_out1 = hz_out3; - hz_out2 = hz_out4; - hz_out3 = hz_out5; - hz_out4 = hz_out6; - } -} - -static void avc_luma_midv_qrt_and_aver_dst_8w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t vert_offset) -{ - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16u8 dst0, dst1, dst2, dst3; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 res0, res1, res2, res3; - v8i16 res4, res5, res6, res7; - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - src += (5 * src_stride); - - hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - res4 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - res6 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - - if (vert_offset) { - res1 = __msa_srari_h(hz_out3, 5); - res3 = __msa_srari_h(hz_out4, 5); - res5 = __msa_srari_h(hz_out5, 5); - res7 = __msa_srari_h(hz_out6, 5); - } else { - res1 = __msa_srari_h(hz_out2, 5); - res3 = __msa_srari_h(hz_out3, 5); - res5 = __msa_srari_h(hz_out4, 5); - res7 = __msa_srari_h(hz_out5, 5); - } - - SAT_SH4_SH(res1, res3, res5, res7, 7); - - res0 = __msa_aver_s_h(res0, res1); - res1 = __msa_aver_s_h(res2, res3); - res2 = __msa_aver_s_h(res4, res5); - res3 = __msa_aver_s_h(res6, res7); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(res0, res1, res2, res3, dst0, dst1, - dst, dst_stride); - dst += (4 * dst_stride); - - hz_out0 = hz_out4; - hz_out1 = hz_out5; - hz_out2 = hz_out6; - hz_out3 = hz_out7; - hz_out4 = hz_out8; - } -} - -static void avc_luma_midv_qrt_and_aver_dst_16w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t vert_offset) -{ - int32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_midv_qrt_and_aver_dst_8w_msa(src, src_stride, dst, dst_stride, - height, vert_offset); - - src += 8; - dst += 8; - } -} - -static void avc_luma_hv_qrt_and_aver_dst_4x4_msa(const uint8_t *src_x, - const uint8_t *src_y, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride) -{ - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4; - v16i8 src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, vert_out0, vert_out1; - v8i16 res0, res1; - v16u8 res; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); - - src_vt0 = (v16i8) __msa_insve_w((v4i32) src_vt0, 1, (v4i32) src_vt1); - src_vt1 = (v16i8) __msa_insve_w((v4i32) src_vt1, 1, (v4i32) src_vt2); - src_vt2 = (v16i8) __msa_insve_w((v4i32) src_vt2, 1, (v4i32) src_vt3); - src_vt3 = (v16i8) __msa_insve_w((v4i32) src_vt3, 1, (v4i32) src_vt4); - - XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz0, src_hz1, - mask0, mask1, mask2); - hz_out1 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz2, src_hz3, - mask0, mask1, mask2); + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz1, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz2, src_hz3, mask0, mask1, mask2); + SRARI_H2_SH(hz_out0, hz_out1, 5); SAT_SH2_SH(hz_out0, hz_out1, 7); - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); @@ -1761,132 +135,511 @@ static void avc_luma_hv_qrt_and_aver_dst_4x4_msa(const uint8_t *src_x, src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); + ILVR_B2_SB(src_vt1, src_vt0, src_vt3, src_vt2, src_vt10_r, src_vt32_r); + ILVR_B2_SB(src_vt5, src_vt4, src_vt7, src_vt6, src_vt54_r, src_vt76_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + SRARI_H2_SH(vt_out0, vt_out1, 5); + SAT_SH2_SH(vt_out0, vt_out1, 7); - /* filter calc */ - vert_out0 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt0, src_vt1, src_vt2, - src_vt3, src_vt4, src_vt5); - vert_out1 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt2, src_vt3, src_vt4, - src_vt5, src_vt6, src_vt7); - SRARI_H2_SH(vert_out0, vert_out1, 5); - SAT_SH2_SH(vert_out0, vert_out1, 7); + out0 = __msa_srari_h((hz_out0 + vt_out0), 1); + out1 = __msa_srari_h((hz_out1 + vt_out1), 1); - res1 = __msa_srari_h((hz_out1 + vert_out1), 1); - res0 = __msa_srari_h((hz_out0 + vert_out0), 1); + SAT_SH2_SH(out0, out1, 7); + out = PCKEV_XORI128_UB(out0, out1); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} + +static void avc_luma_hv_qrt_8x8_msa(const uint8_t *src_x, const uint8_t *src_y, + uint8_t *dst, int32_t stride) +{ + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out0, out1; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, mask0, mask1, mask2; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt7, src_vt8, src_vt9, src_vt10, src_vt11, src_vt12; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, src_vt98_r, src_vt109_r; + v16i8 src_vt1110_r, src_vt1211_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, tmp0, tmp1, tmp2, tmp3; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); + + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, src_vt4, + src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, src_vt8, + src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, filt1, + filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + LD_SB4(src_y, stride, src_vt9, src_vt10, src_vt11, src_vt12); + XORI_B4_128_SB(src_vt9, src_vt10, src_vt11, src_vt12); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + ILVR_B4_SB(src_vt9, src_vt8, src_vt10, src_vt9, src_vt11, src_vt10, + src_vt12, src_vt11, src_vt98_r, src_vt109_r, src_vt1110_r, + src_vt1211_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt54_r, src_vt76_r, src_vt98_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt65_r, src_vt87_r, src_vt109_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt76_r, src_vt98_r, src_vt1110_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt87_r, src_vt109_r, src_vt1211_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); +} + +static void avc_luma_hv_qrt_16x16_msa(const uint8_t *src_x, + const uint8_t *src_y, uint8_t *dst, + int32_t stride) +{ + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + const uint8_t *src_x_tmp = src_x; + const uint8_t *src_y_tmp = src_y; + uint8_t *dst_tmp = dst; + uint32_t multiple8_cnt, loop_cnt; + v16u8 tmp0, tmp1; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, mask0, mask1, mask2; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt7, src_vt8; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, out0, out1, out2, out3; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + src_x = src_x_tmp; + src_y = src_y_tmp; + dst = dst_tmp; + + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); + + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, + src_vt4, src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, + src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, + src_vt8, src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, + src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, + filt1, filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, + filt1, filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, + filt1, filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + out0 = __msa_srari_h((hz_out0 + vt_out0), 1); + out1 = __msa_srari_h((hz_out1 + vt_out1), 1); + out2 = __msa_srari_h((hz_out2 + vt_out2), 1); + out3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + SAT_SH4_SH(out0, out1, out2, out3, 7); + tmp0 = PCKEV_XORI128_UB(out0, out1); + tmp1 = PCKEV_XORI128_UB(out2, out3); + ST8x4_UB(tmp0, tmp1, dst, stride); + dst += (4 * stride); + + src_vt0 = src_vt4; + src_vt1 = src_vt5; + src_vt2 = src_vt6; + src_vt3 = src_vt7; + src_vt4 = src_vt8; + } + + src_x_tmp += 8; + src_y_tmp += 8; + dst_tmp += 8; + } +} + +static void avc_luma_hv_qrt_and_aver_dst_4x4_msa(const uint8_t *src_x, + const uint8_t *src_y, + uint8_t *dst, + int32_t stride) +{ + uint32_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 res, dst0 = { 0 }; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, src_vt7, src_vt8; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt10_r, src_vt32_r, src_vt54_r, src_vt76_r; + v16i8 mask0, mask1, mask2, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, vt_out0, vt_out1, res0, res1; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); + + src_vt0 = (v16i8) __msa_insve_w((v4i32) src_vt0, 1, (v4i32) src_vt1); + src_vt1 = (v16i8) __msa_insve_w((v4i32) src_vt1, 1, (v4i32) src_vt2); + src_vt2 = (v16i8) __msa_insve_w((v4i32) src_vt2, 1, (v4i32) src_vt3); + src_vt3 = (v16i8) __msa_insve_w((v4i32) src_vt3, 1, (v4i32) src_vt4); + + XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); + + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz1, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz2, src_hz3, mask0, mask1, mask2); + + SRARI_H2_SH(hz_out0, hz_out1, 5); + SAT_SH2_SH(hz_out0, hz_out1, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + + src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); + src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); + src_vt6 = (v16i8) __msa_insve_w((v4i32) src_vt6, 1, (v4i32) src_vt7); + src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); + + XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); + ILVR_B2_SB(src_vt1, src_vt0, src_vt3, src_vt2, src_vt10_r, src_vt32_r); + ILVR_B2_SB(src_vt5, src_vt4, src_vt7, src_vt6, src_vt54_r, src_vt76_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + SRARI_H2_SH(vt_out0, vt_out1, 5); + SAT_SH2_SH(vt_out0, vt_out1, 7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + + res1 = __msa_srari_h((hz_out1 + vt_out1), 1); + res0 = __msa_srari_h((hz_out0 + vt_out0), 1); SAT_SH2_SH(res0, res1, 7); res = PCKEV_XORI128_UB(res0, res1); - - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst1 = (v16u8) __msa_insve_w((v4i32) dst2, 1, (v4i32) dst3); - dst0 = (v16u8) __msa_insve_d((v2i64) dst0, 1, (v2i64) dst1); dst0 = __msa_aver_u_b(res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } static void avc_luma_hv_qrt_and_aver_dst_8x8_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride) + int32_t stride) { - uint32_t loop_cnt; - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3; - v16i8 src_vt4, src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 vert_out0, vert_out1, vert_out2, vert_out3; - v8i16 out0, out1, out2, out3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, src_vt0, src_vt1, src_vt2; + v16i8 src_vt3, src_vt4, src_vt5, src_vt6, src_vt7, src_vt8; + v16i8 src_vt9, src_vt10, src_vt11, src_vt12, mask0, mask1, mask2; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, src_vt98_r, src_vt109_r; + v16i8 src_vt1110_r, src_vt1211_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, tmp0, tmp1, tmp2, tmp3; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_vt0 = (v16i8) __msa_insve_d((v2i64) src_vt0, 1, (v2i64) src_vt1); - src_vt1 = (v16i8) __msa_insve_d((v2i64) src_vt1, 1, (v2i64) src_vt2); - src_vt2 = (v16i8) __msa_insve_d((v2i64) src_vt2, 1, (v2i64) src_vt3); - src_vt3 = (v16i8) __msa_insve_d((v2i64) src_vt3, 1, (v2i64) src_vt4); + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); - XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - src_x += (4 * src_stride); + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); - SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); - SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - src_y += (4 * src_stride); + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); - src_vt4 = (v16i8) __msa_insve_d((v2i64) src_vt4, 1, (v2i64) src_vt5); - src_vt5 = (v16i8) __msa_insve_d((v2i64) src_vt5, 1, (v2i64) src_vt6); - src_vt6 = (v16i8) __msa_insve_d((v2i64) src_vt6, 1, (v2i64) src_vt7); - src_vt7 = (v16i8) __msa_insve_d((v2i64) src_vt7, 1, (v2i64) src_vt8); + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, src_vt4, + src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, src_vt8, + src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, filt1, + filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt0, src_vt1, src_vt2, src_vt3, - src_vt4, src_vt5, vert_out0, vert_out1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt2, src_vt3, src_vt4, src_vt5, - src_vt6, src_vt7, vert_out2, vert_out3); - SRARI_H4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 5); - SAT_SH4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 7); + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); - out0 = __msa_srari_h((hz_out0 + vert_out0), 1); - out1 = __msa_srari_h((hz_out1 + vert_out1), 1); - out2 = __msa_srari_h((hz_out2 + vert_out2), 1); - out3 = __msa_srari_h((hz_out3 + vert_out3), 1); + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - SAT_SH4_SH(out0, out1, out2, out3, 7); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(out0, out1, out2, out3, dst0, dst1, - dst, dst_stride); - dst += (4 * dst_stride); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); - src_vt0 = src_vt4; - src_vt1 = src_vt5; - src_vt2 = src_vt6; - src_vt3 = src_vt7; - src_vt4 = src_vt8; - } + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); + + LD_SB4(src_y, stride, src_vt9, src_vt10, src_vt11, src_vt12); + XORI_B4_128_SB(src_vt9, src_vt10, src_vt11, src_vt12); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + ILVR_B4_SB(src_vt9, src_vt8, src_vt10, src_vt9, src_vt11, src_vt10, + src_vt12, src_vt11, src_vt98_r, src_vt109_r, src_vt1110_r, + src_vt1211_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt54_r, src_vt76_r, src_vt98_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt65_r, src_vt87_r, src_vt109_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt76_r, src_vt98_r, src_vt1110_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt87_r, src_vt109_r, src_vt1211_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); } static void avc_luma_hv_qrt_and_aver_dst_16x16_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride) + int32_t stride) { - uint32_t multiple8_cnt; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + const uint8_t *src_x_tmp = src_x; + const uint8_t *src_y_tmp = src_y; + uint8_t *dst_tmp = dst; + uint32_t multiple8_cnt, loop_cnt; + uint64_t tp0, tp1, tp2, tp3; + v16u8 tmp0, tmp1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, mask0, mask1, mask2; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt7, src_vt8; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, out0, out1, out2, out3; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src_x, src_y, src_stride, - dst, dst_stride); + src_x = src_x_tmp; + src_y = src_y_tmp; + dst = dst_tmp; - src_x += 8; - src_y += 8; - dst += 8; - } + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); - src_x += (8 * src_stride) - 16; - src_y += (8 * src_stride) - 16; - dst += (8 * dst_stride) - 16; + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src_x, src_y, src_stride, - dst, dst_stride); + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); - src_x += 8; - src_y += 8; - dst += 8; + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, + src_vt4, src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, + src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, + src_vt8, src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, + src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, + filt1, filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, + filt1, filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, + filt1, filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + out0 = __msa_srari_h((hz_out0 + vt_out0), 1); + out1 = __msa_srari_h((hz_out1 + vt_out1), 1); + out2 = __msa_srari_h((hz_out2 + vt_out2), 1); + out3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + SAT_SH4_SH(out0, out1, out2, out3, 7); + tmp0 = PCKEV_XORI128_UB(out0, out1); + tmp1 = PCKEV_XORI128_UB(out2, out3); + AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); + + src_vt0 = src_vt4; + src_vt1 = src_vt5; + src_vt2 = src_vt6; + src_vt3 = src_vt7; + src_vt4 = src_vt8; + } + + src_x_tmp += 8; + src_y_tmp += 8; + dst_tmp += 8; } } @@ -2766,90 +1519,78 @@ void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, void ff_put_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src - 2, - src - (stride * 2), stride, dst, stride, 16); + avc_luma_hv_qrt_16x16_msa(src - 2, src - (stride * 2), dst, stride); } void ff_put_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 16); + avc_luma_hv_qrt_16x16_msa(src - 2, src - (stride * 2) + 1, dst, stride); } void ff_put_h264_qpel16_mc13_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src + stride - 2, - src - (stride * 2), stride, dst, stride, 16); + avc_luma_hv_qrt_16x16_msa(src + stride - 2, src - (stride * 2), dst, + stride); } void ff_put_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 16); + avc_luma_hv_qrt_16x16_msa(src + stride - 2, src - (stride * 2) + 1, dst, + stride); } void ff_put_h264_qpel8_mc11_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src - 2, src - (stride * 2), stride, dst, stride, 8); + avc_luma_hv_qrt_8x8_msa(src - 2, src - (stride * 2), dst, stride); } void ff_put_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 8); + avc_luma_hv_qrt_8x8_msa(src - 2, src - (stride * 2) + 1, dst, stride); } void ff_put_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src + stride - 2, - src - (stride * 2), stride, dst, stride, 8); + avc_luma_hv_qrt_8x8_msa(src + stride - 2, src - (stride * 2), dst, stride); } void ff_put_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 8); + avc_luma_hv_qrt_8x8_msa(src + stride - 2, src - (stride * 2) + 1, dst, + stride); } void ff_put_h264_qpel4_mc11_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src - 2, src - (stride * 2), stride, dst, stride, 4); + avc_luma_hv_qrt_4x4_msa(src - 2, src - (stride * 2), dst, stride); } void ff_put_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 4); + avc_luma_hv_qrt_4x4_msa(src - 2, src - (stride * 2) + 1, dst, stride); } void ff_put_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src + stride - 2, - src - (stride * 2), stride, dst, stride, 4); + avc_luma_hv_qrt_4x4_msa(src + stride - 2, src - (stride * 2), dst, stride); } void ff_put_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 4); + avc_luma_hv_qrt_4x4_msa(src + stride - 2, src - (stride * 2) + 1, dst, + stride); } void ff_put_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, @@ -3634,153 +2375,1645 @@ void ff_put_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, void ff_put_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 0); + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); + + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + PCKEV_H2_SH(dst2, dst0, dst3, dst1, dst0, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } void ff_put_h264_qpel16_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 1); + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); + + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + dst0 = __msa_pckod_h(dst2, dst0); + dst1 = __msa_pckod_h(dst3, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } void ff_put_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_8w_msa(src - (2 * stride) - 2, stride, dst, stride, 8, 0); + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + PCKEV_H2_SH(dst2, dst0, dst3, dst1, dst0, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); + + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; + } } void ff_put_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_8w_msa(src - (2 * stride) - 2, stride, dst, stride, 8, 1); + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + dst0 = __msa_pckod_h(dst2, dst0); + dst1 = __msa_pckod_h(dst3, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); + + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; + } } void ff_put_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_4w_msa(src - (2 * stride) - 2, stride, dst, stride, 4, 0); + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + ILVEV_H2_SH(dst0, zeros, dst1, zeros, dst0, dst1); + ILVEV_H2_SH(dst2, zeros, dst3, zeros, dst2, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); + + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_4w_msa(src - (2 * stride) - 2, stride, dst, stride, 4, 1); + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + + dst0 = __msa_ilvod_h(zeros, dst0); + dst1 = __msa_ilvod_h(zeros, dst1); + dst2 = __msa_ilvod_h(zeros, dst2); + dst3 = __msa_ilvod_h(zeros, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); + + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_16w_msa(src - (2 * stride) - 2, stride, dst, stride, 16); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint8_t *dst_tmp = dst; + uint32_t multiple8_cnt, loop_cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, dst2, dst3; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + src = src_tmp; + dst = dst_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); + + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } + + src_tmp += 8; + dst_tmp += 8; + } } void ff_put_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_8w_msa(src - (2 * stride) - 2, stride, dst, stride, 8); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, dst0, dst1, dst2, dst3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + src -= ((2 * stride) + 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + hz_out9 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); } void ff_put_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_4w_msa(src - (2 * stride) - 2, stride, dst, stride, 4); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 res; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + res = PCKEV_XORI128_UB(dst0, dst1); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_16x16_msa(src - 2, stride, dst, stride, 0); + uint32_t loop_cnt; + v16u8 dst0, dst1, dst2, dst3; + v16i8 out0, out1, out2, out3, src0, src1, src2, src3, src4, src5, src6; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, src7, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + mask3 = mask0 + 8; + mask4 = mask1 + 8; + mask5 = mask2 + 8; + src -= 2; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, 16, src0, src1); + src += stride; + LD_SB2(src, 16, src2, src3); + src += stride; + LD_SB2(src, 16, src4, src5); + src += stride; + LD_SB2(src, 16, src6, src7); + src += stride; + + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src2, src2, src2, src3, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src2, src2, src2, src3, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src2, src2, src2, src3, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res0, res1, res2, res3); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src4, src5, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src6, src6, src6, src7, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src4, src4, src4, src5, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src6, src6, src6, src7, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src4, src4, src4, src5, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src6, src6, src6, src7, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res4, res5, res6, res7); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SLDI_B2_SB(src1, src3, src0, src2, src0, src2, 2); + SLDI_B2_SB(src5, src7, src4, src6, src4, src6, 2); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_SB(res5, res4, res7, res6, out2, out3); + out0 = __msa_aver_s_b(out0, src0); + out1 = __msa_aver_s_b(out1, src2); + out2 = __msa_aver_s_b(out2, src4); + out3 = __msa_aver_s_b(out3, src6); + XORI_B4_128_SB(out0, out1, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + AVER_UB2_UB(out2, dst2, out3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); + } } void ff_avg_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_16x16_msa(src - 2, stride, dst, stride, 1); + uint32_t loop_cnt; + v16u8 dst0, dst1, dst2, dst3; + v16i8 out0, out1, out2, out3, src0, src1, src2, src3, src4, src5, src6; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, src7, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + mask3 = mask0 + 8; + mask4 = mask1 + 8; + mask5 = mask2 + 8; + src -= 2; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, 16, src0, src1); + src += stride; + LD_SB2(src, 16, src2, src3); + src += stride; + LD_SB2(src, 16, src4, src5); + src += stride; + LD_SB2(src, 16, src6, src7); + src += stride; + + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src2, src2, src2, src3, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src2, src2, src2, src3, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src2, src2, src2, src3, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res0, res1, res2, res3); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src4, src5, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src6, src6, src6, src7, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src4, src4, src4, src5, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src6, src6, src6, src7, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src4, src4, src4, src5, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src6, src6, src6, src7, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res4, res5, res6, res7); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SLDI_B2_SB(src1, src3, src0, src2, src0, src2, 3); + SLDI_B2_SB(src5, src7, src4, src6, src4, src6, 3); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_SB(res5, res4, res7, res6, out2, out3); + out0 = __msa_aver_s_b(out0, src0); + out1 = __msa_aver_s_b(out1, src2); + out2 = __msa_aver_s_b(out2, src4); + out3 = __msa_aver_s_b(out3, src6); + XORI_B4_128_SB(out0, out1, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + AVER_UB2_UB(out2, dst2, out3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); + } } void ff_avg_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_8x8_msa(src - 2, stride, dst, stride, 0); + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 tmp0, tmp1, tmp2, tmp3, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res4, res5, res6, res7); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 2); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 2); + SLDI_B2_SB(src4, src5, src4, src5, src4, src5, 2); + SLDI_B2_SB(src6, src7, src6, src7, src6, src7, 2); + PCKEV_D2_SB(src1, src0, src3, src2, src0, src1); + PCKEV_D2_SB(src5, src4, src7, src6, src4, src5); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, tmp0, tmp1); + PCKEV_B2_SB(res5, res4, res7, res6, tmp2, tmp3); + tmp0 = __msa_aver_s_b(tmp0, src0); + tmp1 = __msa_aver_s_b(tmp1, src1); + tmp2 = __msa_aver_s_b(tmp2, src4); + tmp3 = __msa_aver_s_b(tmp3, src5); + XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); + AVER_UB2_UB(tmp2, dst2, tmp3, dst3, dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } void ff_avg_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_8x8_msa(src - 2, stride, dst, stride, 1); + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 tmp0, tmp1, tmp2, tmp3, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res4, res5, res6, res7); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 3); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 3); + SLDI_B2_SB(src4, src5, src4, src5, src4, src5, 3); + SLDI_B2_SB(src6, src7, src6, src7, src6, src7, 3); + PCKEV_D2_SB(src1, src0, src3, src2, src0, src1); + PCKEV_D2_SB(src5, src4, src7, src6, src4, src5); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, tmp0, tmp1); + PCKEV_B2_SB(res5, res4, res7, res6, tmp2, tmp3); + tmp0 = __msa_aver_s_b(tmp0, src0); + tmp1 = __msa_aver_s_b(tmp1, src1); + tmp2 = __msa_aver_s_b(tmp2, src4); + tmp3 = __msa_aver_s_b(tmp3, src5); + XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); + AVER_UB2_UB(tmp2, dst2, tmp3, dst3, dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } void ff_avg_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_4x4_msa(src - 2, stride, dst, stride, 0); + uint32_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }; + v16i8 src0, src1, src2, src3, res, vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 mask0, mask1, mask2; + v8i16 out0, out1; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_SB4(src - 2, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + HADD_SB2_SH(vec0, vec1, out0, out1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, out0, out1); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, out0, out1); + SRARI_H2_SH(out0, out1, 5); + SAT_SH2_SH(out0, out1, 7); + res = __msa_pckev_b((v16i8) out1, (v16i8) out0); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 2); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 2); + src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); + src1 = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); + res = __msa_aver_s_b(res, src0); + res = (v16i8) __msa_xori_b((v16u8) res, 128); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + dst0 = __msa_aver_u_b((v16u8) res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_4x4_msa(src - 2, stride, dst, stride, 1); + uint32_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }; + v16i8 src0, src1, src2, src3, res, vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 mask0, mask1, mask2; + v8i16 out0, out1; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_SB4(src - 2, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + HADD_SB2_SH(vec0, vec1, out0, out1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, out0, out1); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, out0, out1); + SRARI_H2_SH(out0, out1, 5); + SAT_SH2_SH(out0, out1, 7); + res = __msa_pckev_b((v16i8) out1, (v16i8) out0); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 3); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 3); + src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); + src1 = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); + res = __msa_aver_s_b(res, src0); + res = (v16i8) __msa_xori_b((v16u8) res, 128); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + dst0 = __msa_aver_u_b((v16u8) res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_and_aver_dst_16x16_msa(src - 2, stride, dst, stride); + uint32_t loop_cnt; + v16u8 dst0, dst1, dst2, dst3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v16i8 vec11; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + src -= 2; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, 8, src0, src1); + src += stride; + LD_SB2(src, 8, src2, src3); + src += stride; + LD_SB2(src, 8, src4, src5); + src += stride; + LD_SB2(src, 8, src6, src7); + src += stride; + + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec1, vec4); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec7, vec10); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec2, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res0, res1, res2, res3); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec3); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec6, vec9); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec1, vec4); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec7, vec10); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec2, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res4, res5, res6, res7); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, vec0, vec1, + vec2, vec3); + XORI_B4_128_SB(vec0, vec1, vec2, vec3); + AVER_UB2_UB(vec0, dst0, vec1, dst1, dst0, dst1); + AVER_UB2_UB(vec2, dst2, vec3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); + } } void ff_avg_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_and_aver_dst_8x8_msa(src - 2, stride, dst, stride); + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, out2 = { 0 }, out3 = { 0 }; + v16u8 out4, out5, out6 = { 0 }, out7 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v16i8 vec11; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res4, res5, res6, res7); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + out4 = PCKEV_XORI128_UB(res4, res5); + out5 = PCKEV_XORI128_UB(res6, res7); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, out2); + INSERT_D2_UB(tp2, tp3, out3); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, out6); + INSERT_D2_UB(tp2, tp3, out7); + AVER_UB2_UB(out0, out2, out1, out3, out0, out1); + AVER_UB2_UB(out4, out6, out5, out7, out4, out5); + ST8x8_UB(out0, out1, out4, out5, dst, stride); } void ff_avg_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_and_aver_dst_4x4_msa(src - 2, stride, dst, stride); + uint32_t tp0, tp1, tp2, tp3; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 mask0, mask1, mask2; + v8i16 res0, res1; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_SB4(src - 2, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + HADD_SB2_SH(vec0, vec1, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); + SRARI_H2_SH(res0, res1, 5); + SAT_SH2_SH(res0, res1, 7); + res = PCKEV_XORI128_UB(res0, res1); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = __msa_aver_u_b(res, dst0); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_16x16_msa(src - (stride * 2), - stride, dst, stride, 0); + int32_t loop_cnt; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res0, res1, res2, res3, dst0, dst1, dst2, dst3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; + v16i8 src65_l, src87_l, filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, + src65_r, src76_r, src87_r); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, + src65_l, src76_l, src87_l); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out0_l = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + out1_l = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + out2_l = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + out3_l = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, res0, res1, res2, res3); + res0 = (v16u8) __msa_aver_s_b((v16i8) res0, src2); + res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src3); + res2 = (v16u8) __msa_aver_s_b((v16i8) res2, src4); + res3 = (v16u8) __msa_aver_s_b((v16i8) res3, src5); + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); + XORI_B4_128_UB(res0, res1, res2, res3); + AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); + AVER_UB2_UB(res2, dst2, res3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); + + src10_r = src54_r; + src32_r = src76_r; + src21_r = src65_r; + src43_r = src87_r; + src10_l = src54_l; + src32_l = src76_l; + src21_l = src65_l; + src43_l = src87_l; + src2 = src6; + src3 = src7; + src4 = src8; + } } void ff_avg_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_16x16_msa(src - (stride * 2), - stride, dst, stride, 1); + int32_t loop_cnt; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res0, res1, res2, res3, dst0, dst1, dst2, dst3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; + v16i8 src65_l, src87_l, filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, + src65_r, src76_r, src87_r); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, + src65_l, src76_l, src87_l); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out0_l = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + out1_l = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + out2_l = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + out3_l = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, res0, res1, res2, res3); + res0 = (v16u8) __msa_aver_s_b((v16i8) res0, src3); + res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src4); + res2 = (v16u8) __msa_aver_s_b((v16i8) res2, src5); + res3 = (v16u8) __msa_aver_s_b((v16i8) res3, src6); + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); + XORI_B4_128_UB(res0, res1, res2, res3); + AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); + AVER_UB2_UB(res2, dst2, res3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); + + src10_r = src54_r; + src32_r = src76_r; + src21_r = src65_r; + src43_r = src87_r; + src10_l = src54_l; + src32_l = src76_l; + src21_l = src65_l; + src43_l = src87_l; + src3 = src7; + src4 = src8; + } } void ff_avg_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_8x8_msa(src - (stride * 2), - stride, dst, stride, 0); + uint64_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10, src11, src12; + v16i8 src13, src14, tmp0, tmp1, tmp2, tmp3, src109_r; + v16i8 src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; + v16i8 filt0, filt1, filt2, out0, out1, out2, out3; + v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + LD_SB8(src, stride, src7, src8, src9, src10, src11, src12, src13, src14); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); + ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); + PCKEV_D2_SB(src3, src2, src7, src4, tmp0, tmp1); + ILVR_B4_SB(src11, src10, src12, src11, src13, src12, src14, src13, src10_r, + src21_r, src32_r, src43_r); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src10_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src21_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src10_r, src32_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src21_r, src43_r, filt0, filt1, filt2); + PCKEV_D2_SB(src9, src8, src11, src10, tmp2, tmp3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + + PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, out0, out1); + PCKEV_B2_SB(out5_r, out4_r, out7_r, out6_r, out2, out3); + out0 = __msa_aver_s_b(out0, tmp0); + out1 = __msa_aver_s_b(out1, tmp1); + out2 = __msa_aver_s_b(out2, tmp2); + out3 = __msa_aver_s_b(out3, tmp3); + XORI_B4_128_SB(out0, out1, out2, out3); + AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } void ff_avg_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_8x8_msa(src - (stride * 2), - stride, dst, stride, 1); + uint64_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10, src11, src12; + v16i8 src13, src14, tmp0, tmp1, tmp2, tmp3, src109_r; + v16i8 src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; + v16i8 filt0, filt1, filt2, out0, out1, out2, out3; + v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + LD_SB8(src, stride, src7, src8, src9, src10, src11, src12, src13, src14); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); + ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); + PCKEV_D2_SB(src4, src3, src8, src7, tmp0, tmp1); + ILVR_B4_SB(src11, src10, src12, src11, src13, src12, src14, src13, src10_r, + src21_r, src32_r, src43_r); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src10_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src21_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src10_r, src32_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src21_r, src43_r, filt0, filt1, filt2); + PCKEV_D2_SB(src10, src9, src12, src11, tmp2, tmp3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + + PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, out0, out1); + PCKEV_B2_SB(out5_r, out4_r, out7_r, out6_r, out2, out3); + out0 = __msa_aver_s_b(out0, tmp0); + out1 = __msa_aver_s_b(out1, tmp1); + out2 = __msa_aver_s_b(out2, tmp2); + out3 = __msa_aver_s_b(out3, tmp3); + XORI_B4_128_SB(out0, out1, out2, out3); + AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } void ff_avg_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_4x4_msa(src - (stride * 2), - stride, dst, stride, 0); + uint32_t tp0, tp1, tp2, tp3; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; + v8i16 out10, out32; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + LD_SB4(src, stride, src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); + XORI_B2_128_SB(src6554, src8776); + src32_r = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); + src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); + out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); + out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); + SRARI_H2_SH(out10, out32, 5); + SAT_SH2_SH(out10, out32, 7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(out10, out32); + res = __msa_aver_u_b(res, (v16u8) src32_r); + dst0 = __msa_aver_u_b(res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_4x4_msa(src - (stride * 2), - stride, dst, stride, 1); + uint32_t tp0, tp1, tp2, tp3; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; + v8i16 out10, out32; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + LD_SB4(src, stride, src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); + XORI_B2_128_SB(src6554, src8776); + out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); + out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); + SRARI_H2_SH(out10, out32, 5); + SAT_SH2_SH(out10, out32, 7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(out10, out32); + src32_r = (v16i8) __msa_insve_w((v4i32) src3, 1, (v4i32) src4); + src54_r = (v16i8) __msa_insve_w((v4i32) src5, 1, (v4i32) src6); + src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); + res = __msa_aver_u_b(res, (v16u8) src32_r); + dst0 = __msa_aver_u_b(res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, @@ -3788,7 +4021,7 @@ void ff_avg_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_16x16_msa(src - 2, src - (stride * 2), - stride, dst, stride); + dst, stride); } void ff_avg_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, @@ -3796,7 +4029,7 @@ void ff_avg_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_16x16_msa(src - 2, src - (stride * 2) + - sizeof(uint8_t), stride, + sizeof(uint8_t), dst, stride); } @@ -3805,7 +4038,7 @@ void ff_avg_h264_qpel16_mc13_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_16x16_msa(src + stride - 2, src - (stride * 2), - stride, dst, stride); + dst, stride); } void ff_avg_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, @@ -3813,7 +4046,7 @@ void ff_avg_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_16x16_msa(src + stride - 2, src - (stride * 2) + - sizeof(uint8_t), stride, + sizeof(uint8_t), dst, stride); } @@ -3822,7 +4055,7 @@ void ff_avg_h264_qpel8_mc11_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_8x8_msa(src - 2, src - (stride * 2), - stride, dst, stride); + dst, stride); } void ff_avg_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, @@ -3830,7 +4063,7 @@ void ff_avg_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_8x8_msa(src - 2, src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); + sizeof(uint8_t), dst, stride); } void ff_avg_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, @@ -3838,7 +4071,7 @@ void ff_avg_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_8x8_msa(src + stride - 2, src - (stride * 2), - stride, dst, stride); + dst, stride); } void ff_avg_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, @@ -3846,7 +4079,7 @@ void ff_avg_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_8x8_msa(src + stride - 2, src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); + sizeof(uint8_t), dst, stride); } @@ -3855,7 +4088,7 @@ void ff_avg_h264_qpel4_mc11_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_4x4_msa(src - 2, src - (stride * 2), - stride, dst, stride); + dst, stride); } void ff_avg_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, @@ -3863,7 +4096,7 @@ void ff_avg_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_4x4_msa(src - 2, src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); + sizeof(uint8_t), dst, stride); } void ff_avg_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, @@ -3871,7 +4104,7 @@ void ff_avg_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_4x4_msa(src + stride - 2, src - (stride * 2), - stride, dst, stride); + dst, stride); } void ff_avg_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, @@ -3879,128 +4112,1678 @@ void ff_avg_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, { avc_luma_hv_qrt_and_aver_dst_4x4_msa(src + stride - 2, src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); + sizeof(uint8_t), dst, stride); } void ff_avg_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 0); + uint64_t tp0, tp1, tp2, tp3; + uint8_t *dst_tmp = dst; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint32_t multiple8_cnt, loop_cnt; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, mask0, mask1; + v16i8 mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0_w, tmp1_w; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + dst = dst_tmp; + src = src_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + + XORI_B2_128_SB(src5, src6); + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_r, + hz_out65_r); + ILVL_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_l, + hz_out65_l); + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp1 = __msa_srari_h(hz_out2, 5); + tmp3 = __msa_srari_h(hz_out3, 5); + SAT_SH2_SH(tmp1, tmp3, 7); + + tmp0 = __msa_aver_s_h(tmp0, tmp1); + tmp1 = __msa_aver_s_h(tmp2, tmp3); + + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + dst0 = __msa_aver_u_b(out0, dst0); + ST8x2_UB(dst0, dst, stride); + dst += (2 * stride); + + LD_SB2(src, stride, src7, src8); + src += (2 * stride); + + XORI_B2_128_SB(src7, src8); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + ILVR_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_r, + hz_out87_r); + ILVL_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_l, + hz_out87_l); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + tmp4 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + tmp6 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp5 = __msa_srari_h(hz_out4, 5); + tmp7 = __msa_srari_h(hz_out5, 5); + SAT_SH2_SH(tmp5, tmp7, 7); + + tmp2 = __msa_aver_s_h(tmp4, tmp5); + tmp3 = __msa_aver_s_h(tmp6, tmp7); + + LD2(dst, stride, tp2, tp3); + INSERT_D2_UB(tp2, tp3, dst1); + + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + dst1 = __msa_aver_u_b(out1, dst1); + ST8x2_UB(dst1, dst, stride); + dst += (2 * stride); + + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } + + src_tmp += 8; + dst_tmp += 8; + } } void ff_avg_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 1); + uint64_t tp0, tp1, tp2, tp3; + uint8_t *dst_tmp = dst; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint32_t multiple8_cnt, loop_cnt; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, mask0, mask1; + v16i8 mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0_w, tmp1_w; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + dst = dst_tmp; + src = src_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + + XORI_B2_128_SB(src5, src6); + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_r, hz_out65_r); + ILVL_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_l, hz_out65_l); + + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp1 = __msa_srari_h(hz_out3, 5); + tmp3 = __msa_srari_h(hz_out4, 5); + SAT_SH2_SH(tmp1, tmp3, 7); + + tmp0 = __msa_aver_s_h(tmp0, tmp1); + tmp1 = __msa_aver_s_h(tmp2, tmp3); + + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + dst0 = __msa_aver_u_b(out0, dst0); + ST8x2_UB(dst0, dst, stride); + dst += (2 * stride); + + LD_SB2(src, stride, src7, src8); + src += (2 * stride); + + XORI_B2_128_SB(src7, src8); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + ILVR_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_r, + hz_out87_r); + ILVL_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_l, + hz_out87_l); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + tmp4 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + tmp6 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp5 = __msa_srari_h(hz_out5, 5); + tmp7 = __msa_srari_h(hz_out6, 5); + SAT_SH2_SH(tmp5, tmp7, 7); + + tmp2 = __msa_aver_s_h(tmp4, tmp5); + tmp3 = __msa_aver_s_h(tmp6, tmp7); + + LD2(dst, stride, tp2, tp3); + INSERT_D2_UB(tp2, tp3, dst1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + dst1 = __msa_aver_u_b(out1, dst1); + ST8x2_UB(dst1, dst, stride); + dst += (2 * stride); + + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } + + src_tmp += 8; + dst_tmp += 8; + } } void ff_avg_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 0); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, tmp0, tmp1, tmp2, tmp3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0_w, tmp1_w; + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); + + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + SRARI_H4_SH(hz_out2, hz_out3, hz_out4, hz_out5, 5); + SAT_SH4_SH(hz_out2, hz_out3, hz_out4, hz_out5, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + tmp0 = __msa_aver_s_h(tmp0, hz_out2); + tmp1 = __msa_aver_s_h(tmp1, hz_out3); + tmp2 = __msa_aver_s_h(tmp2, hz_out4); + tmp3 = __msa_aver_s_h(tmp3, hz_out5); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); + + LD_SB4(src, stride, src9, src10, src11, src12); + XORI_B4_128_SB(src9, src10, src11, src12); + hz_out9 = AVC_HORZ_FILTER_SH(src9, src9, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src10, src10, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src11, src11, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src12, src12, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0_w = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + SRARI_H4_SH(hz_out6, hz_out7, hz_out8, hz_out9, 5); + SAT_SH4_SH(hz_out6, hz_out7, hz_out8, hz_out9, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + tmp0 = __msa_aver_s_h(tmp0, hz_out6); + tmp1 = __msa_aver_s_h(tmp1, hz_out7); + tmp2 = __msa_aver_s_h(tmp2, hz_out8); + tmp3 = __msa_aver_s_h(tmp3, hz_out9); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } void ff_avg_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 1); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, tmp0, tmp1, tmp2, tmp3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0_w, tmp1_w; + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); + + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + SRARI_H4_SH(hz_out3, hz_out4, hz_out5, hz_out6, 5); + SAT_SH4_SH(hz_out3, hz_out4, hz_out5, hz_out6, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + tmp0 = __msa_aver_s_h(tmp0, hz_out3); + tmp1 = __msa_aver_s_h(tmp1, hz_out4); + tmp2 = __msa_aver_s_h(tmp2, hz_out5); + tmp3 = __msa_aver_s_h(tmp3, hz_out6); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); + + LD_SB4(src, stride, src9, src10, src11, src12); + XORI_B4_128_SB(src9, src10, src11, src12); + hz_out9 = AVC_HORZ_FILTER_SH(src9, src9, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src10, src10, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src11, src11, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src12, src12, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0_w = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + SRARI_H4_SH(hz_out7, hz_out8, hz_out9, hz_out10, 5); + SAT_SH4_SH(hz_out7, hz_out8, hz_out9, hz_out10, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + tmp0 = __msa_aver_s_h(tmp0, hz_out7); + tmp1 = __msa_aver_s_h(tmp1, hz_out8); + tmp2 = __msa_aver_s_h(tmp2, hz_out9); + tmp3 = __msa_aver_s_h(tmp3, hz_out10); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } void ff_avg_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 0); + uint32_t tp0, tp1, tp2, tp3; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 res, out = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + SRARI_H2_SH(hz_out2, hz_out4, 5); + SAT_SH2_SH(hz_out2, hz_out4, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out2); + dst1 = __msa_aver_s_h(dst1, hz_out4); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, out); + res = PCKEV_XORI128_UB(dst0, dst1); + res = __msa_aver_u_b(res, out); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 1); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint32_t tp0, tp1, tp2, tp3; + v16u8 res, out = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + PCKEV_D2_SH(hz_out4, hz_out3, hz_out6, hz_out5, hz_out0, hz_out1); + SRARI_H2_SH(hz_out0, hz_out1, 5); + SAT_SH2_SH(hz_out0, hz_out1, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out0); + dst1 = __msa_aver_s_h(dst1, hz_out1); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, out); + res = PCKEV_XORI128_UB(dst0, dst1); + res = __msa_aver_u_b(res, out); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_and_aver_dst_16x16_msa(src - (stride * 2), stride, dst, stride); + int32_t loop_cnt; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res0, res1, res2, res3, dst0, dst1, dst2, dst3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; + v16i8 src65_l, src87_l, filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, + src65_r, src76_r, src87_r); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, + src65_l, src76_l, src87_l); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out0_l = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + out1_l = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + out2_l = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + out3_l = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, res0, res1, res2, res3); + XORI_B4_128_UB(res0, res1, res2, res3); + AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); + AVER_UB2_UB(res2, dst2, res3, dst3, res2, res3); + ST_UB4(res0, res1, res2, res3, dst, stride); + dst += (4 * stride); + + src10_r = src54_r; + src32_r = src76_r; + src21_r = src65_r; + src43_r = src87_r; + src10_l = src54_l; + src32_l = src76_l; + src21_l = src65_l; + src43_l = src87_l; + src4 = src8; + } } void ff_avg_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_and_aver_dst_8x8_msa(src - (stride * 2), stride, dst, stride); + uint64_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10, src109_r; + v16i8 src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; + v16i8 filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + + LD_SB4(src, stride, src7, src8, src9, src10); + src += (4 * stride); + XORI_B4_128_SB(src7, src8, src9, src10); + ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); + + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + ILVR_B4_SB(src0, src10, src1, src0, src2, src1, src3, src2, src10_r, + src21_r, src32_r, src43_r); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src10_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src21_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src10_r, src32_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src21_r, src43_r, filt0, filt1, filt2); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + out0 = PCKEV_XORI128_UB(out0_r, out1_r); + out1 = PCKEV_XORI128_UB(out2_r, out3_r); + out2 = PCKEV_XORI128_UB(out4_r, out5_r); + out3 = PCKEV_XORI128_UB(out6_r, out7_r); + AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } void ff_avg_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_and_aver_dst_4x4_msa(src - (stride * 2), stride, dst, stride); + uint32_t tp0, tp1, tp2, tp3; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; + v8i16 out10, out32; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + LD_SB4(src, stride, src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); + XORI_B2_128_SB(src6554, src8776); + out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); + out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); + SRARI_H2_SH(out10, out32, 5); + SAT_SH2_SH(out10, out32, 7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(out10, out32); + dst0 = __msa_aver_u_b(res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 0); + uint32_t row; + v16u8 out, dst0; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); + + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); + dst0 = LD_UB(dst); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + PCKEV_H2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } void ff_avg_h264_qpel16_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 1); + uint32_t row; + v16u8 out, dst0; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); + + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); + dst0 = LD_UB(dst); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + tmp0 = __msa_pckod_h(tmp2, tmp0); + tmp1 = __msa_pckod_h(tmp3, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } void ff_avg_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 0); + uint32_t row; + uint64_t tp0, tp1; + v16u8 out, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + PCKEV_H2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); + + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; + } } void ff_avg_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 1); + uint32_t row; + uint64_t tp0, tp1; + v16u8 out, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + tmp0 = __msa_pckod_h(tmp2, tmp0); + tmp1 = __msa_pckod_h(tmp3, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); + + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; + } } void ff_avg_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 0); + uint32_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out, dstv = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + ILVEV_H2_SH(dst0, zeros, dst1, zeros, dst0, dst1); + ILVEV_H2_SH(dst2, zeros, dst3, zeros, dst2, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); + + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dstv); + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + out = __msa_aver_u_b(out, dstv); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 1); + uint32_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out, dstv = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); + + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + + dst0 = __msa_ilvod_h(zeros, dst0); + dst1 = __msa_ilvod_h(zeros, dst1); + dst2 = __msa_ilvod_h(zeros, dst2); + dst3 = __msa_ilvod_h(zeros, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); + + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dstv); + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + out = __msa_aver_u_b(out, dstv); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_and_aver_dst_16x16_msa(src - (2 * stride) - 2, - stride, dst, stride); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint8_t *dst_tmp = dst; + uint64_t tp0, tp1, tp2, tp3; + uint32_t multiple8_cnt, loop_cnt; + v16u8 dst0, dst1, out0, out1; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, res0, res1, res2, res3; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + src = src_tmp; + dst = dst_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); + + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + res2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + res3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } + + src_tmp += 8; + dst_tmp += 8; + } } void ff_avg_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, res0, res1, res2, res3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + src -= ((2 * stride) + 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + res2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + res3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); + + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + hz_out9 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + res2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + res3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } void ff_avg_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_and_aver_dst_4x4_msa(src - (2 * stride) - 2, - stride, dst, stride); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint32_t tp0, tp1, tp2, tp3; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, res0, res1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(res0, res1); + res = __msa_aver_u_b(res, dst0); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } diff --git a/libavcodec/mips/hevc_macros_msa.h b/libavcodec/mips/hevc_macros_msa.h index 7dcfea03b..ea53812b6 100644 --- a/libavcodec/mips/hevc_macros_msa.h +++ b/libavcodec/mips/hevc_macros_msa.h @@ -21,43 +21,6 @@ #ifndef AVCODEC_MIPS_HEVC_MACROS_MSA_H #define AVCODEC_MIPS_HEVC_MACROS_MSA_H -#define HEVC_PCK_SW_SB2(in0, in1, out) \ -{ \ - v8i16 tmp0_m; \ - \ - tmp0_m = __msa_pckev_h((v8i16) in0, (v8i16) in1); \ - out = (v4i32) __msa_pckev_b((v16i8) tmp0_m, (v16i8) tmp0_m); \ -} - -#define HEVC_PCK_SW_SB4(in0, in1, in2, in3, out) \ -{ \ - v8i16 tmp0_m, tmp1_m; \ - \ - PCKEV_H2_SH(in0, in1, in2, in3, tmp0_m, tmp1_m); \ - out = (v4i32) __msa_pckev_b((v16i8) tmp1_m, (v16i8) tmp0_m); \ -} - -#define HEVC_PCK_SW_SB8(in0, in1, in2, in3, in4, in5, in6, in7, out0, out1) \ -{ \ - v8i16 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \ - \ - PCKEV_H4_SH(in0, in1, in2, in3, in4, in5, in6, in7, \ - tmp0_m, tmp1_m, tmp2_m, tmp3_m); \ - PCKEV_B2_SW(tmp1_m, tmp0_m, tmp3_m, tmp2_m, out0, out1); \ -} - -#define HEVC_PCK_SW_SB12(in0, in1, in2, in3, in4, in5, in6, in7, \ - in8, in9, in10, in11, out0, out1, out2) \ -{ \ - v8i16 tmp0_m, tmp1_m, tmp2_m, tmp3_m, tmp4_m, tmp5_m; \ - \ - PCKEV_H4_SH(in0, in1, in2, in3, in4, in5, in6, in7, \ - tmp0_m, tmp1_m, tmp2_m, tmp3_m); \ - PCKEV_H2_SH(in8, in9, in10, in11, tmp4_m, tmp5_m); \ - PCKEV_B2_SW(tmp1_m, tmp0_m, tmp3_m, tmp2_m, out0, out1); \ - out2 = (v4i32) __msa_pckev_b((v16i8) tmp5_m, (v16i8) tmp4_m); \ -} - #define HEVC_FILT_8TAP_SH(in0, in1, in2, in3, \ filt0, filt1, filt2, filt3) \ ( { \ @@ -80,6 +43,15 @@ out_m; \ } ) +#define HEVC_FILT_4TAP_SH(in0, in1, filt0, filt1) \ +( { \ + v8i16 out_m; \ + \ + out_m = __msa_dotp_s_h((v16i8) in0, (v16i8) filt0); \ + out_m = __msa_dpadd_s_h(out_m, (v16i8) in1, (v16i8) filt1); \ + out_m; \ +} ) + #define HEVC_FILT_4TAP(in0, in1, filt0, filt1) \ ( { \ v4i32 out_m; \ diff --git a/libavcodec/mips/hevc_mc_bi_msa.c b/libavcodec/mips/hevc_mc_bi_msa.c index 8208be327..b555517b2 100644 --- a/libavcodec/mips/hevc_mc_bi_msa.c +++ b/libavcodec/mips/hevc_mc_bi_msa.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) + * Copyright (c) 2015 - 2017 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) * * This file is part of FFmpeg. * @@ -22,6 +22,12 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 +}; + #define HEVC_BI_RND_CLIP2(in0, in1, vec0, vec1, rnd_val, out0, out1) \ { \ ADDS_SH2_SH(vec0, in0, vec1, in1, out0, out1); \ @@ -37,6 +43,21 @@ HEVC_BI_RND_CLIP2(in2, in3, vec2, vec3, rnd_val, out2, out3); \ } +#define HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, rnd_val, \ + out0, out1) \ +{ \ + ADDS_SH2_SH(vec0, in0, vec1, in1, out0, out1); \ + SRARI_H2_SH(out0, out1, rnd_val); \ + CLIP_SH2_0_255_MAX_SATU(out0, out1); \ +} + +#define HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, vec0, vec1, vec2, \ + vec3, rnd_val, out0, out1, out2, out3) \ +{ \ + HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, rnd_val, out0, out1); \ + HEVC_BI_RND_CLIP2_MAX_SATU(in2, in3, vec2, vec3, rnd_val, out2, out3); \ +} + static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, @@ -45,71 +66,59 @@ static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { + uint32_t loop_cnt, tp0, tp1, tp2, tp3; + uint64_t tpd0, tpd1, tpd2, tpd3; + v16i8 src0 = { 0 }, src1 = { 0 }; v16i8 zero = { 0 }; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst0, dst1, dst2, dst3; if (2 == height) { - v16i8 src0, src1; - v8i16 dst0, in0, in1; - - LD_SB2(src0_ptr, src_stride, src0, src1); - LD_SH2(src1_ptr, src2_stride, in0, in1); - - src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); + LW2(src0_ptr, src_stride, tp0, tp1); + INSERT_W2_SB(tp0, tp1, src0); + LD2(src1_ptr, src2_stride, tpd0, tpd1); + INSERT_D2_SH(tpd0, tpd1, in0); dst0 = (v8i16) __msa_ilvr_b(zero, src0); dst0 <<= 6; dst0 += in0; dst0 = __msa_srari_h(dst0, 7); - dst0 = CLIP_SH_0_255(dst0); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); dst0 = (v8i16) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); ST4x2_UB(dst0, dst, dst_stride); } else if (4 == height) { - v16i8 src0, src1, src2, src3; - v8i16 dst0, dst1; - v8i16 in0, in1, in2, in3; - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_W2_SB(src1, src0, src3, src2, src0, src1); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - - dst0 <<= 6; - dst1 <<= 6; - HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); - + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); + HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, dst0, dst1, 7, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == height % 8) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v8i16 dst0, dst1, dst2, dst3; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB8(src0_ptr, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src0_ptr += (8 * src_stride); - - LD_SH8(src1_ptr, src2_stride, - in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); - - ILVR_W4_SB(src1, src0, src3, src2, src5, src4, src7, src6, - src0, src1, src2, src3); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in2); + INSERT_D2_SH(tpd2, tpd3, in3); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); - + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, + dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); ST4x8_UB(dst0, dst1, dst, dst_stride); dst += (8 * dst_stride); @@ -126,36 +135,39 @@ static void hevc_bi_copy_6w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, out2, out3; v16i8 zero = { 0 }; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB8(src0_ptr, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src0_ptr += (8 * src_stride); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src2); + INSERT_D2_SB(tp2, tp3, src3); LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, in7); src1_ptr += (8 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - ILVR_B4_SH(zero, src4, zero, src5, zero, src6, zero, src7, - dst4, dst5, dst6, dst7); - + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); SLLI_4V(dst0, dst1, dst2, dst3, 6); SLLI_4V(dst4, dst5, dst6, dst7, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST6x4_UB(dst0, dst1, dst, dst_stride); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST6x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - - HEVC_BI_RND_CLIP4(in4, in5, in6, in7, - dst4, dst5, dst6, dst7, 7, dst4, dst5, dst6, dst7); - - PCKEV_B2_SH(dst5, dst4, dst7, dst6, dst4, dst5); - ST6x4_UB(dst4, dst5, dst, dst_stride); + ST6x4_UB(out2, out3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -168,100 +180,83 @@ static void hevc_bi_copy_8w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, out2, out3; + v16i8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; v16i8 zero = { 0 }; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; if (2 == height) { - v16i8 src0, src1; - v8i16 in0, in1; - v8i16 dst0, dst1; - - LD_SB2(src0_ptr, src_stride, src0, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src0); LD_SH2(src1_ptr, src2_stride, in0, in1); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - - dst0 <<= 6; - dst1 <<= 6; - HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); - - dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(dst0, dst, dst_stride); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); + HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, dst0, dst1, 7, dst0, dst1); + out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out0, dst, dst_stride); } else if (4 == height) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1, dst2, dst3; - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); } else if (6 == height) { - v16i8 src0, src1, src2, src3, src4, src5; - v8i16 in0, in1, in2, in3, in4, in5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - - LD_SB6(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src2); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - ILVR_B2_SH(zero, src4, zero, src5, dst4, dst5); - SLLI_4V(dst0, dst1, dst2, dst3, 6); - dst4 <<= 6; - dst5 <<= 6; - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - HEVC_BI_RND_CLIP2(in4, in5, dst4, dst5, 7, dst4, dst5); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - dst2 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST8x4_UB(dst0, dst1, dst, dst_stride); + SLLI_2V(dst4, dst5, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP2_MAX_SATU(in4, in5, dst4, dst5, 7, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } else if (0 == height % 8) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1, dst2, dst3; uint32_t loop_cnt; for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src2); + INSERT_D2_SB(tp2, tp3, src3); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, + in7); + src1_ptr += (8 * src2_stride); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - - SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, + dst3, 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, + dst7, 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + dst += (8 * dst_stride); } } } @@ -275,12 +270,13 @@ static void hevc_bi_copy_12w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; + v16i8 zero = { 0 }; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v16i8 zero = { 0 }; - for (loop_cnt = (16 >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); @@ -288,88 +284,21 @@ static void hevc_bi_copy_12w_msa(uint8_t *src0_ptr, LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); src1_ptr += (4 * src2_stride); ILVR_D2_SH(in5, in4, in7, in6, in4, in5); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, dst0, dst1, + dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); ILVL_W2_SB(src1, src0, src3, src2, src0, src1); ILVR_B2_SH(zero, src0, zero, src1, dst4, dst5); - dst4 <<= 6; - dst5 <<= 6; - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - HEVC_BI_RND_CLIP2(in4, in5, dst4, dst5, 7, dst4, dst5); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - dst2 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST12x4_UB(dst0, dst1, dst2, dst, dst_stride); + SLLI_2V(dst4, dst5, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP2_MAX_SATU(in4, in5, dst4, dst5, 7, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); } } -static void hevc_bi_copy_16multx4mult_msa(uint8_t *src0_ptr, - int32_t src_stride, - int16_t *src1_ptr, - int32_t src2_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - int32_t width) -{ - uint32_t loop_cnt; - uint32_t cnt; - uint8_t *src0_ptr_tmp; - int16_t *src1_ptr_tmp; - uint8_t *dst_tmp; - v16i8 zero = { 0 }; - - for (cnt = (width >> 4); cnt--;) { - src0_ptr_tmp = src0_ptr; - src1_ptr_tmp = src1_ptr; - dst_tmp = dst; - - for (loop_cnt = (height >> 2); loop_cnt--;) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst0_l, dst1_l, dst2_l, dst3_l; - - LD_SB4(src0_ptr_tmp, src_stride, src0, src1, src2, src3); - src0_ptr_tmp += (4 * src_stride); - LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); - LD_SH4(src1_ptr_tmp + 8, src2_stride, in4, in5, in6, in7); - src1_ptr_tmp += (4 * src2_stride); - - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0_r, dst1_r, dst2_r, dst3_r); - ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0_l, dst1_l, dst2_l, dst3_l); - - SLLI_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); - SLLI_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); - HEVC_BI_RND_CLIP4(in0, in1, in4, in5, - dst0_r, dst1_r, dst0_l, dst1_l, 7, - dst0_r, dst1_r, dst0_l, dst1_l); - - PCKEV_B2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); - ST_SH2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - - HEVC_BI_RND_CLIP4(in2, in3, in6, in7, - dst2_r, dst3_r, dst2_l, dst3_l, 7, - dst2_r, dst3_r, dst2_l, dst3_l); - - PCKEV_B2_SH(dst2_l, dst2_r, dst3_l, dst3_r, dst2_r, dst3_r); - ST_SH2(dst2_r, dst3_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - } - - src0_ptr += 16; - src1_ptr += 16; - dst += 16; - } -} - static void hevc_bi_copy_16w_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, @@ -378,8 +307,34 @@ static void hevc_bi_copy_16w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 16); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v16i8 zero = { 0 }; + + for (loop_cnt = (height >> 2); loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + src1_ptr += (4 * src2_stride); + ILVRL_B2_SH(zero, src0, dst0_r, dst0_l); + ILVRL_B2_SH(zero, src1, dst1_r, dst1_l); + ILVRL_B2_SH(zero, src2, dst2_r, dst2_l); + ILVRL_B2_SH(zero, src3, dst3_r, dst3_l); + SLLI_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SLLI_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in4, in5, dst0_r, dst1_r, dst0_l, + dst1_l, 7, dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_BI_RND_CLIP4_MAX_SATU(in2, in3, in6, in7, dst2_r, dst3_r, dst2_l, + dst3_l, 7, dst2_r, dst3_r, dst2_l, dst3_l); + PCKEV_B2_UB(dst0_l, dst0_r, dst1_l, dst1_r, out0, out1); + PCKEV_B2_UB(dst2_l, dst2_r, dst3_l, dst3_r, out2, out3); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_bi_copy_24w_msa(uint8_t *src0_ptr, @@ -390,11 +345,42 @@ static void hevc_bi_copy_24w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 16); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, dst11; - hevc_bi_copy_8w_msa(src0_ptr + 16, src_stride, src1_ptr + 16, src2_stride, - dst + 16, dst_stride, height); + for (loop_cnt = 8; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src4, src5); + LD_SB4(src0_ptr + 16, src_stride, src2, src3, src6, src7); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + LD_SH4(src1_ptr + 16, src2_stride, in8, in9, in10, in11); + src1_ptr += (4 * src2_stride); + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVR_B2_SH(zero, src2, zero, src3, dst4, dst5); + ILVRL_B2_SH(zero, src4, dst6, dst7); + ILVRL_B2_SH(zero, src5, dst8, dst9); + ILVR_B2_SH(zero, src6, zero, src7, dst10, dst11); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + SLLI_4V(dst8, dst9, dst10, dst11, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in4, in1, in5, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in8, in9, in2, in6, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + HEVC_BI_RND_CLIP4_MAX_SATU(in3, in7, in10, in11, dst8, dst9, dst10, + dst11, 7, dst8, dst9, dst10, dst11); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST_UB4(out0, out1, out3, out4, dst, dst_stride); + ST8x4_UB(out2, out5, dst + 16, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_bi_copy_32w_msa(uint8_t *src0_ptr, @@ -405,8 +391,40 @@ static void hevc_bi_copy_32w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 32); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SB2(src0_ptr, 16, src2, src3); + src0_ptr += src_stride; + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + src1_ptr += src2_stride; + LD_SH4(src1_ptr, 8, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST_UB2(out0, out1, dst, 16); + dst += dst_stride; + ST_UB2(out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_bi_copy_48w_msa(uint8_t *src0_ptr, @@ -417,8 +435,50 @@ static void hevc_bi_copy_48w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 48); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, dst11; + + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB3(src0_ptr, 16, src0, src1, src2); + src0_ptr += src_stride; + LD_SB3(src0_ptr, 16, src3, src4, src5); + src0_ptr += src_stride; + + LD_SH6(src1_ptr, 8, in0, in1, in2, in3, in4, in5); + src1_ptr += src2_stride; + LD_SH6(src1_ptr, 8, in6, in7, in8, in9, in10, in11); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + ILVRL_B2_SH(zero, src4, dst8, dst9); + ILVRL_B2_SH(zero, src5, dst10, dst11); + + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + SLLI_4V(dst8, dst9, dst10, dst11, 6); + + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + HEVC_BI_RND_CLIP4_MAX_SATU(in8, in9, in10, in11, dst8, dst9, dst10, + dst11, 7, dst8, dst9, dst10, dst11); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST_UB2(out0, out1, dst, 16); + ST_UB(out2, dst + 32); + dst += dst_stride; + ST_UB2(out3, out4, dst, 16); + ST_UB(out5, dst + 32); + dst += dst_stride; + } } static void hevc_bi_copy_64w_msa(uint8_t *src0_ptr, @@ -429,8 +489,35 @@ static void hevc_bi_copy_64w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 64); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + + for (loop_cnt = height; loop_cnt--;) { + LD_SB4(src0_ptr, 16, src0, src1, src2, src3); + src0_ptr += src_stride; + LD_SH8(src1_ptr, 8, in0, in1, in2, in3, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + + ST_UB4(out0, out1, out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, @@ -450,7 +537,7 @@ static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src0_ptr -= 3; @@ -476,26 +563,26 @@ static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - VSHF_B4_SB(src0, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src2, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src4, src5, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src6, src7, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -523,7 +610,7 @@ static void hevc_hz_bi_8t_8w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; @@ -544,26 +631,26 @@ static void hevc_hz_bi_8t_8w_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -583,10 +670,83 @@ static void hevc_hz_bi_8t_12w_msa(uint8_t *src0_ptr, const int8_t *filter, int32_t height) { - hevc_hz_bi_8t_8w_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height); - hevc_hz_bi_8t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter, height); + uint32_t loop_cnt; + int32_t tmp0, tmp1; + int64_t tmp2, tmp3; + v16i8 src0, src1, src2, src3; + v16i8 vec0, vec1, vec2; + v8i16 filt0, filt1, filt2, filt3; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v8i16 dst0, dst1, dst2; + v8i16 in0, in1, in2, in3; + v8i16 filter_vec, const_vec; + + src0_ptr -= 3; + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + filter_vec = LD_SH(filter); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + mask4 = LD_SB(&ff_hevc_mask_arr[16]); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB2(src0_ptr, 8, src0, src1); + src0_ptr += src_stride; + LD_SB2(src0_ptr, 8, src2, src3); + src0_ptr += src_stride; + LD_SH2(src1_ptr, 8, in0, in1); + src1_ptr += src2_stride; + LD_SH2(src1_ptr, 8, in2, in3); + src1_ptr += src2_stride; + XORI_B4_128_SB(src0, src1, src2, src3); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask0, mask4, mask0, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt0, filt0, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt0); + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask1, mask5, mask1, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt1, filt1, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt1); + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask2, mask6, mask2, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt2, filt2, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt2); + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask3, mask7, mask3, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt3, filt3, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt3); + + in1 = (v8i16) __msa_pckev_d((v2i64) in3, (v2i64) in1); + HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); + dst2 = __msa_adds_s_h(in2, dst2); + dst2 = __msa_srari_h(dst2, 7); + dst2 = CLIP_SH_0_255(dst2); + PCKEV_B2_SH(dst1, dst0, dst2, dst2, dst0, dst1); + + tmp2 = __msa_copy_s_d((v2i64) dst0, 0); + tmp0 = __msa_copy_s_w((v4i32) dst0, 2); + tmp3 = __msa_copy_s_d((v2i64) dst1, 0); + tmp1 = __msa_copy_s_w((v4i32) dst0, 3); + SD(tmp2, dst); + SW(tmp0, dst + 8); + dst += dst_stride; + SD(tmp3, dst); + SW(tmp1, dst + 8); + dst += dst_stride; + } } static void hevc_hz_bi_8t_16w_msa(uint8_t *src0_ptr, @@ -606,7 +766,7 @@ static void hevc_hz_bi_8t_16w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; const_vec = __msa_ldi_h(128); @@ -630,26 +790,26 @@ static void hevc_hz_bi_8t_16w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -678,7 +838,7 @@ static void hevc_hz_bi_8t_24w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2; v8i16 in0, in1, in2; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr = src0_ptr - 3; const_vec = __msa_ldi_h(128); @@ -703,21 +863,21 @@ static void hevc_hz_bi_8t_24w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B2_128_SB(src0, src1); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src0, src0, mask0, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt1, dst0, + dst1, dst2, dst0); + VSHF_B2_SB(src0, src1, src1, src1, mask5, mask1, vec0, vec1); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt2, filt2, dst1, + dst2, dst0, dst1); + VSHF_B2_SB(src1, src1, src0, src0, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src0, src1, src1, src1, mask7, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt3, filt3, filt3, dst2, + dst0, dst1, dst2); HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); dst2 = __msa_adds_s_h(dst2, in2); @@ -749,7 +909,7 @@ static void hevc_hz_bi_8t_32w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; const_vec = __msa_ldi_h(128); @@ -774,26 +934,26 @@ static void hevc_hz_bi_8t_32w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B3_128_SB(src0, src1, src2); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -822,7 +982,7 @@ static void hevc_hz_bi_8t_48w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 in0, in1, in2, in3, in4, in5; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; @@ -840,62 +1000,53 @@ static void hevc_hz_bi_8t_48w_msa(uint8_t *src0_ptr, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB2(src0_ptr, 16, src0, src1); - XORI_B2_128_SB(src0, src1); - LD_SH2(src1_ptr, 8, in0, in1); - - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - - HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); - - tmp0 = __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST_SB(tmp0, dst); - - LD_SB2(src0_ptr + 32, 8, src2, src3); - XORI_B2_128_SB(src2, src3); + for (loop_cnt = 64; loop_cnt--;) { + LD_SB3(src0_ptr, 16, src0, src1, src2); + src3 = LD_SB(src0_ptr + 40); src0_ptr += src_stride; + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + XORI_B4_128_SB(src0, src1, src2, src3); - LD_SH2(src1_ptr + 16, 8, in2, in3); - - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); + dst0 = const_vec; + dst1 = const_vec; dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src1, src2, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask0, mask4, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask1, mask5, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask2, mask6, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask3, mask7, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); HEVC_BI_RND_CLIP2(in2, in3, dst2, dst3, 7, dst2, dst3); - - tmp1 = __msa_pckev_b((v16i8) dst3, (v16i8) dst2); + PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); + ST_SB(tmp0, dst); ST_SB(tmp1, dst + 16); LD_SH2(src1_ptr + 32, 8, in4, in5); src1_ptr += src2_stride; - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, dst4, + dst5, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt3, filt3, dst4, + dst5, dst4, dst5); HEVC_BI_RND_CLIP2(in4, in5, dst4, dst5, 7, dst4, dst5); @@ -914,14 +1065,10 @@ static void hevc_hz_bi_8t_64w_msa(uint8_t *src0_ptr, const int8_t *filter, int32_t height) { - uint8_t *src0_ptr_tmp; - uint8_t *dst_tmp; - int16_t *src1_ptr_tmp; uint32_t loop_cnt; - uint32_t cnt; - v16i8 src0, src1, src2, tmp0, tmp1; + v16i8 src0, src1, src2, src3, src4, src5, tmp0, tmp1; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; @@ -945,48 +1092,74 @@ static void hevc_hz_bi_8t_64w_msa(uint8_t *src0_ptr, mask7 = mask0 + 14; for (loop_cnt = height; loop_cnt--;) { - src0_ptr_tmp = src0_ptr; - dst_tmp = dst; - src1_ptr_tmp = src1_ptr; + LD_SB2(src0_ptr, 16, src0, src1); + src2 = LD_SB(src0_ptr + 24); + LD_SB2(src0_ptr + 32, 16, src3, src4); + src5 = LD_SB(src0_ptr + 56); + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + XORI_B3_128_SB(src0, src1, src2); - for (cnt = 2; cnt--;) { - LD_SB2(src0_ptr_tmp, 16, src0, src1); - src2 = LD_SB(src0_ptr_tmp + 24); - src0_ptr_tmp += 32; - LD_SH4(src1_ptr_tmp, 8, in0, in1, in2, in3); - src1_ptr_tmp += 32; - XORI_B3_128_SB(src0, src1, src2); + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + dst3 = const_vec; - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0, dst1, dst2, dst3, 7, + dst0, dst1, dst2, dst3); - PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); - ST_SB2(tmp0, tmp1, dst_tmp, 16); - dst_tmp += 32; - } + PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); + ST_SB2(tmp0, tmp1, dst, 16); + src0 = src3; + src1 = src4; + src2 = src5; + + LD_SH4(src1_ptr + 32, 8, in0, in1, in2, in3); + XORI_B3_128_SB(src0, src1, src2); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + dst3 = const_vec; + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0, dst1, dst2, dst3, 7, + dst0, dst1, dst2, dst3); + PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); + ST_SB2(tmp0, tmp1, dst + 32, 16); src1_ptr += src2_stride; src0_ptr += src_stride; dst += dst_stride; @@ -1447,30 +1620,30 @@ static void hevc_hv_bi_8t_4w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v8i16 in0, in1; + uint64_t tp0, tp1; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v8i16 in0 = { 0 }, in1 = { 0 }; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r, in0_r, in0_l; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 out0, out1; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10, dst32, dst54, dst76, dst98, dst21, dst43, dst65, dst87, dst109; + v4i32 dst0, dst1, dst2, dst3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src0_ptr -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1491,71 +1664,77 @@ static void hevc_hv_bi_8t_4w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src0_ptr, src_stride, src7, src8); - src0_ptr += (2 * src_stride); - LD_SH2(src1_ptr, src2_stride, in0, in1); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); src1_ptr += (2 * src2_stride); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src7, src8); - - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); - dst0_r >>= 6; - dst1_r >>= 6; - UNPCK_SH_SW(in0, in0_r, in0_l); - dst0_r = __msa_adds_s_w(dst0_r, in0_r); - dst1_r = __msa_adds_s_w(dst1_r, in0_l); - SRARI_W2_SW(dst0_r, dst1_r, 7); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); + dst0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + dst2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, out0, out1); + ADDS_SH2_SH(out0, in0, out1, in1, out0, out1); + ADDS_SH2_SH(out0, const_vec, out1, const_vec, out0, out1); + SRARI_H2_SH(out0, out1, 7); + CLIP_SH2_0_255_MAX_SATU(out0, out1); + out = (v16u8) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } -static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, +static void hevc_hv_bi_8t_8multx1mult_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, int32_t src2_stride, @@ -1570,22 +1749,20 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v8i16 in0, in1; - v4i32 in0_r, in0_l, in1_r, in1_l; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v8i16 in0, tmp; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; - v4i32 dst0_r, dst0_l, dst1_r, dst1_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 dst0_r, dst0_l; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst10_l, dst32_l, dst54_l, dst76_l; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v8i16 dst21_l, dst43_l, dst65_l, dst87_l; src0_ptr -= ((3 * src_stride) + 3); const_vec = __msa_ldi_h(128); @@ -1595,9 +1772,9 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1622,18 +1799,14 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1641,38 +1814,28 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, vec4, vec5, vec6, vec7); VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + for (loop_cnt = height; loop_cnt--;) { + src7 = LD_SB(src0_ptr_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src0_ptr_tmp += src_stride; - for (loop_cnt = height >> 1; loop_cnt--;) { - /* row 7 */ - LD_SB2(src0_ptr_tmp, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - src0_ptr_tmp += 2 * src_stride; - - LD_SH2(src1_ptr_tmp, src2_stride, in0, in1); - src1_ptr_tmp += (2 * src2_stride); + in0 = LD_SH(src1_ptr_tmp); + src1_ptr_tmp += src2_stride; VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); - + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, filt_h1, filt_h2, filt_h3); @@ -1681,49 +1844,21 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, dst0_r >>= 6; dst0_l >>= 6; - VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + tmp = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + ADDS_SH2_SH(tmp, in0, tmp, const_vec, tmp, tmp); + tmp = __msa_srari_h(tmp, 7); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST8x1_UB(out, dst_tmp); + dst_tmp += dst_stride; - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst1_l = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, - filt_h0, filt_h1, filt_h2, filt_h3); - dst1_r >>= 6; - dst1_l >>= 6; - - UNPCK_SH_SW(in0, in0_r, in0_l); - UNPCK_SH_SW(in1, in1_r, in1_l); - in0_r = __msa_adds_s_w(in0_r, dst0_r); - in0_l = __msa_adds_s_w(in0_l, dst0_l); - in1_r = __msa_adds_s_w(in1_r, dst1_r); - in1_l = __msa_adds_s_w(in1_l, dst1_l); - SRARI_W4_SW(in0_r, in0_l, in1_r, in1_l, 7); - in0_r = CLIP_SW_0_255(in0_r); - in0_l = CLIP_SW_0_255(in0_l); - in1_r = CLIP_SW_0_255(in1_r); - in1_l = CLIP_SW_0_255(in1_l); - - HEVC_PCK_SW_SB4(in0_l, in0_r, in1_l, in1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; - dst6 = dst8; + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; } src0_ptr += 8; @@ -1742,7 +1877,7 @@ static void hevc_hv_bi_8t_8w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 8); } @@ -1757,12 +1892,208 @@ static void hevc_hv_bi_8t_12w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, 8); + uint32_t loop_cnt; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + uint64_t tp0, tp1; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 in0, in1 = { 0 }, out0, out1, tmp, filter_vec, const_vec; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10, dst32, dst54, dst76, dst98, dst21, dst43, dst65, dst87, dst109; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r; + v8i16 dst10_l, dst32_l, dst54_l, dst76_l; + v4i32 dst0_r, dst0_l, tmp0, tmp1, tmp2, tmp3; - hevc_hv_bi_8t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, height); + src0_ptr -= ((3 * src_stride) + 3); + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src0_ptr_tmp = src0_ptr; + dst_tmp = dst; + src1_ptr_tmp = src1_ptr; + + LD_SB7(src0_ptr_tmp, src_stride, src0, src1, src2, src3, src4, src5, + src6); + src0_ptr_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, + vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, + vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 16; loop_cnt--;) { + src7 = LD_SB(src0_ptr_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src0_ptr_tmp += src_stride; + + in0 = LD_SH(src1_ptr_tmp); + src1_ptr_tmp += src2_stride; + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + tmp = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + ADDS_SH2_SH(tmp, in0, tmp, const_vec, tmp, tmp); + tmp = __msa_srari_h(tmp, 7); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST8x1_UB(out, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; + } + + src0_ptr += 8; + dst += 8; + src1_ptr += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, + vec8, vec9, vec10, vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, + vec12, vec13, vec14, vec15); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + src1_ptr += (2 * src2_stride); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); + + tmp0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + tmp1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + tmp2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + tmp3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + SRA_4V(tmp0, tmp1, tmp2, tmp3, 6); + PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, out0, out1); + ADDS_SH2_SH(out0, in0, out1, in1, out0, out1); + ADDS_SH2_SH(out0, const_vec, out1, const_vec, out0, out1); + SRARI_H2_SH(out0, out1, 7); + CLIP_SH2_0_255_MAX_SATU(out0, out1); + out = (v16u8) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_bi_8t_16w_msa(uint8_t *src0_ptr, @@ -1775,7 +2106,7 @@ static void hevc_hv_bi_8t_16w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 16); } @@ -1790,7 +2121,7 @@ static void hevc_hv_bi_8t_24w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 24); } @@ -1805,7 +2136,7 @@ static void hevc_hv_bi_8t_32w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 32); } @@ -1820,7 +2151,7 @@ static void hevc_hv_bi_8t_48w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 48); } @@ -1835,7 +2166,7 @@ static void hevc_hv_bi_8t_64w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 64); } @@ -1852,7 +2183,7 @@ static void hevc_hz_bi_4t_4x2_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, dst0, vec0, vec1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v8i16 tmp0; v8i16 filter_vec, const_vec; @@ -1895,7 +2226,8 @@ static void hevc_hz_bi_4t_4x4_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, dst0, vec0, vec1; v8i16 in0, in1, in2, in3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 vec2, vec3; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v8i16 tmp0, tmp1; v8i16 filter_vec, const_vec; @@ -1916,12 +2248,12 @@ static void hevc_hz_bi_4t_4x4_msa(uint8_t *src0_ptr, ILVR_D2_SH(in1, in0, in3, in2, in0, in1); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); tmp0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp0, tmp0); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); tmp1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp1, tmp1); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, tmp0, tmp1, + tmp0, tmp1); HEVC_BI_RND_CLIP2(in0, in1, tmp0, tmp1, 7, tmp0, tmp1); dst0 = __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); @@ -1942,8 +2274,8 @@ static void hevc_hz_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v16i8 dst0, dst1; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v16i8 mask1, vec0, vec1; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); + v16i8 mask1, vec0, vec1, vec2, vec3; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filter_vec, const_vec; @@ -1969,18 +2301,18 @@ static void hevc_hz_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); tmp0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp0, tmp0); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); tmp1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp1, tmp1); - VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec0, vec1); tmp2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp2, tmp2); - VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec0, vec1); tmp3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp3, tmp3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, tmp0, + tmp1, tmp2, tmp3); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, tmp0, + tmp1, tmp2, tmp3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); @@ -2026,9 +2358,9 @@ static void hevc_hz_bi_4t_6w_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; @@ -2049,18 +2381,18 @@ static void hevc_hz_bi_4t_6w_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2083,8 +2415,8 @@ static void hevc_hz_bi_4t_8x2_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; - v16i8 mask1, vec0, vec1; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); + v16i8 mask1, vec0, vec1, vec2, vec3; v8i16 dst0, dst1; v8i16 filter_vec, const_vec; @@ -2102,12 +2434,12 @@ static void hevc_hz_bi_4t_8x2_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in0, in1); XORI_B2_128_SB(src0, src1); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, dst0, dst1, + dst0, dst1); HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); @@ -2126,9 +2458,9 @@ static void hevc_hz_bi_4t_8x6_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3, in4, in5; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; @@ -2148,24 +2480,25 @@ static void hevc_hz_bi_4t_8x6_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in4, in5); XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, dst1, + dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, dst1, + dst2, dst3); dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, dst4, dst5, + dst4, dst5); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2191,9 +2524,9 @@ static void hevc_hz_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; @@ -2214,18 +2547,18 @@ static void hevc_hz_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2271,12 +2604,12 @@ static void hevc_hz_bi_4t_12w_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; v16i8 mask1, mask3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; @@ -2301,24 +2634,24 @@ static void hevc_hz_bi_4t_12w_msa(uint8_t *src0_ptr, ILVR_D2_SH(in5, in4, in7, in6, in4, in5); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2341,13 +2674,11 @@ static void hevc_hz_bi_4t_16w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v16i8 src0, src1, src2, src3, vec0, vec1, vec2, vec3; + v8i16 in0, in1, in2, in3, dst0, dst1, dst2, dst3; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v16i8 vec0, vec1; v8i16 filter_vec, const_vec; src0_ptr -= 1; @@ -2360,49 +2691,36 @@ static void hevc_hz_bi_4t_16w_msa(uint8_t *src0_ptr, mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src2, src4, src6); - LD_SB4(src0_ptr + 8, src_stride, src1, src3, src5, src7); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in2, in4, in6); - LD_SH4(src1_ptr + 8, src2_stride, in1, in3, in5, in7); - src1_ptr += (4 * src2_stride); - XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src0_ptr, src_stride, src0, src2); + LD_SB2(src0_ptr + 8, src_stride, src1, src3); + src0_ptr += (2 * src_stride); + LD_SH2(src1_ptr, src2_stride, in0, in2); + LD_SH2(src1_ptr + 8, src2_stride, in1, in3); + src1_ptr += (2 * src2_stride); + + XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - HEVC_BI_RND_CLIP4(in4, in5, in6, in7, - dst4, dst5, dst6, dst7, 7, dst4, dst5, dst6, dst7); - PCKEV_B4_SH(dst1, dst0, dst3, dst2, - dst5, dst4, dst7, dst6, dst0, dst1, dst2, dst3); - ST_SH4(dst0, dst1, dst2, dst3, dst, dst_stride); - dst += (4 * dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); + dst += (2 * dst_stride); } } @@ -2421,9 +2739,9 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v8i16 filter_vec, const_vec; @@ -2451,30 +2769,31 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src2, src3, mask0, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src2, src3, mask1, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src4, src5, src4, src5, mask2, mask3, vec0, vec1); dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - VSHF_B2_SB(src6, src7, src6, src7, mask2, mask3, vec0, vec1); dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + VSHF_B2_SB(src4, src4, src4, src5, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src6, src6, src6, src7, mask0, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst4, + dst5, dst6, dst7); + VSHF_B2_SB(src4, src4, src4, src5, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src6, src6, src6, src7, mask1, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst4, + dst5, dst6, dst7); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2489,18 +2808,18 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); src1_ptr_tmp += (4 * src2_stride); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src1, src1, src3, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src5, src5, src7, src7, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src1, src1, src3, src3, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src5, src5, src7, src7, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2524,10 +2843,10 @@ static void hevc_hz_bi_4t_32w_msa(uint8_t *src0_ptr, v16i8 src0, src1, src2; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; v8i16 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 filter_vec, const_vec; src0_ptr -= 1; @@ -2542,7 +2861,7 @@ static void hevc_hz_bi_4t_32w_msa(uint8_t *src0_ptr, mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = height; loop_cnt--;) { LD_SB2(src0_ptr, 16, src0, src1); src2 = LD_SB(src0_ptr + 24); src0_ptr += src_stride; @@ -2550,45 +2869,18 @@ static void hevc_hz_bi_4t_32w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST_SH2(dst0, dst1, dst, 16); - dst += dst_stride; - - LD_SB2(src0_ptr, 16, src0, src1); - src2 = LD_SB(src0_ptr + 24); - src0_ptr += src_stride; - LD_SH4(src1_ptr, 8, in0, in1, in2, in3); - src1_ptr += src2_stride; - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2800,10 +3092,9 @@ static void hevc_vt_bi_4t_6w_msa(uint8_t *src0_ptr, const int8_t *filter, int32_t height) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 in0, in1, in2, in3; - v16i8 src10_r, src32_r, src21_r, src43_r; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2818,40 +3109,70 @@ static void hevc_vt_bi_4t_6w_msa(uint8_t *src0_ptr, LD_SB3(src0_ptr, src_stride, src0, src1, src2); src0_ptr += (3 * src_stride); + LD_SB2(src0_ptr, src_stride, src3, src4); + src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src5, src6); + src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src7, src8); + src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src9, src10); + src0_ptr += (2 * src_stride); + + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += (4 * src2_stride); + XORI_B3_128_SB(src0, src1, src2); + XORI_B2_128_SB(src3, src4); + XORI_B2_128_SB(src5, src6); + XORI_B2_128_SB(src7, src8); + XORI_B2_128_SB(src9, src10); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src0_ptr, src_stride, src3, src4); - src0_ptr += (2 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + dst0_r = const_vec; + DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); + dst1_r = const_vec; + DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); - dst0_r = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); - dst1_r = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); - LD_SB2(src0_ptr, src_stride, src5, src2); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); + dst2_r = const_vec; + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + dst3_r = const_vec; + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); - dst2_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst2_r, dst2_r); - dst3_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst3_r, dst3_r); + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0_r, dst1_r, dst2_r, dst3_r, 7, + dst0_r, dst1_r, dst2_r, dst3_r); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0_r, dst1_r, dst2_r, dst3_r, 7, - dst0_r, dst1_r, dst2_r, dst3_r); + PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + dst += (4 * dst_stride); - PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += (4 * src2_stride); + ILVR_B2_SB(src7, src6, src8, src7, src32_r, src43_r); + + dst0_r = const_vec; + DPADD_SB2_SH(src54_r, src32_r, filt0, filt1, dst0_r, dst0_r); + dst1_r = const_vec; + DPADD_SB2_SH(src65_r, src43_r, filt0, filt1, dst1_r, dst1_r); + + ILVR_B2_SB(src9, src8, src10, src9, src54_r, src65_r); + + dst2_r = const_vec; + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + dst3_r = const_vec; + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); + + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0_r, dst1_r, dst2_r, dst3_r, 7, + dst0_r, dst1_r, dst2_r, dst3_r); + + PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + dst += (4 * dst_stride); } static void hevc_vt_bi_4t_8x2_msa(uint8_t *src0_ptr, @@ -3053,12 +3374,12 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 src10_r, src32_r, src21_r, src43_r; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; - v16i8 src2110, src4332; + v16i8 src2110, src4332, src6554; v8i16 dst0_l, dst1_l, filt0, filt1; v8i16 filter_vec, const_vec; @@ -3080,15 +3401,21 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, for (loop_cnt = (height >> 2); loop_cnt--;) { LD_SB2(src0_ptr, src_stride, src3, src4); src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src5, src6); + src0_ptr += (2 * src_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); LD_SH4((src1_ptr + 8), src2_stride, in4, in5, in6, in7); src1_ptr += (4 * src2_stride); ILVR_D2_SH(in5, in4, in7, in6, in4, in5); XORI_B2_128_SB(src3, src4); + XORI_B2_128_SB(src5, src6); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVL_B2_SB(src5, src4, src6, src5, src54_l, src65_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); dst0_r = const_vec; DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); @@ -3096,21 +3423,12 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); dst0_l = const_vec; DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst0_l, dst0_l); - - LD_SB2(src0_ptr, src_stride, src5, src2); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - dst2_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst2_r, dst2_r); + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); dst3_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst3_r, dst3_r); + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); dst1_l = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, dst1_l, dst1_l); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst1_l, dst1_l); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0_r, dst1_r, dst2_r, dst3_r, 7, dst0_r, dst1_r, dst2_r, dst3_r); @@ -3120,6 +3438,11 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, dst0_l = (v8i16) __msa_pckev_b((v16i8) dst1_l, (v16i8) dst0_l); ST12x4_UB(dst0_r, dst1_r, dst0_l, dst, dst_stride); dst += (4 * dst_stride); + + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src2110 = src6554; } } @@ -3449,20 +3772,20 @@ static void hevc_hv_bi_4t_4x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { - v8i16 in0, in1; + uint64_t tp0, tp1; + v16u8 out; + v8i16 in0 = { 0 }; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43, tmp; + v4i32 dst0, dst1; src0_ptr -= (src_stride + 1); @@ -3470,56 +3793,43 @@ static void hevc_hv_bi_4t_4x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + in0 = __msa_adds_s_h(in0, const_vec); - LD_SB2(src0_ptr, src_stride, src3, src4); - LD_SH2(src1_ptr, src2_stride, in0, in1); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src3, src4); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - dst0_r = (v4i32) __msa_adds_s_h((v8i16) dst0_r, in0); - dst0_r = (v4i32) __msa_srari_h((v8i16) dst0_r, 7); - dst0_r = (v4i32) CLIP_SH_0_255(dst0_r); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); - dst0_r = (v4i32) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp = __msa_adds_s_h(tmp, in0); + tmp = __msa_srari_h(tmp, 7); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, @@ -3529,21 +3839,22 @@ static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { - v8i16 in0, in1, in2, in3; + uint64_t tp0, tp1; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 dst0_r, dst1_r; - v4i32 tmp0, tmp1, tmp2, tmp3; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 tmp0, tmp1; + v8i16 in0 = { 0 }, in1 = { 0 }; + v8i16 dst30, dst41, dst52, dst63; + v8i16 dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 dst0, dst1, dst2, dst3; src0_ptr -= (src_stride + 1); @@ -3551,69 +3862,50 @@ static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + ADDS_SH2_SH(in0, const_vec, in1, const_vec, in0, in1); - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - XORI_B4_128_SB(src3, src4, src5, src6); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - tmp0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - tmp0 >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - tmp1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - tmp1 >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst10_r = __msa_ilvr_h(dst5, dst4); - tmp2 = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - tmp2 >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst5); - tmp3 = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - tmp3 >>= 6; - PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - HEVC_BI_RND_CLIP2(in0, in1, dst0_r, dst1_r, 7, dst0_r, dst1_r); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); - dst0_r = (v8i16) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + ADDS_SH2_SH(tmp0, in0, tmp1, in1, tmp0, tmp1); + SRARI_H2_SH(tmp0, tmp1, 7); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, @@ -3627,18 +3919,21 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + uint64_t tp0, tp1; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; + v8i16 dst98_r, dst109_r; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; src0_ptr -= (src_stride + 1); @@ -3647,10 +3942,9 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3661,90 +3955,75 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, src0_ptr += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); src0_ptr += (8 * src_stride); - LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst54_r = __msa_ilvr_h(dst5, dst4); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - dst65_r = __msa_ilvr_h(dst6, dst5); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - dst76_r = __msa_ilvr_h(dst7, dst6); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - dst87_r = __msa_ilvr_h(dst8, dst7); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - /* row 9 */ - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - /* row 10 */ - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); PCKEV_H4_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst5_r, dst4_r, dst7_r, dst6_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); - - PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); - ST4x8_UB(tmp0, tmp1, dst, dst_stride); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, tmp0, tmp1, + tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -3760,10 +4039,10 @@ static void hevc_hv_bi_4t_4w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hv_bi_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); } else if (4 == height) { hevc_hv_bi_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); } else if (0 == (height % 8)) { hevc_hv_bi_4t_4multx8mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -3782,20 +4061,28 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v8i16 in0, in1, in2, in3; + uint32_t tpw0, tpw1, tpw2, tpw3; + uint64_t tp0, tp1; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp4, tmp5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst4_r, dst5_r, dst6_r, dst7_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst54_r, dst76_r, dst98_r, dst65_r, dst87_r, dst109_r; + v8i16 dst54_l, dst76_l, dst98_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 in4 = { 0 }, in5 = { 0 }; src0_ptr -= (src_stride + 1); @@ -3803,10 +4090,9 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3820,71 +4106,101 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - XORI_B4_128_SB(src3, src4, src5, src6); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + LD_SB8(src0_ptr, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr + 2 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); - PCKEV_B2_SW(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + LD2(src1_ptr + 4 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr + 6 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in3); + + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, const_vec, + in0, in1, in2, in3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, tmp0, tmp1, tmp2, + tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + src1_ptr += (4 * src2_stride); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in4); + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in5); + ADDS_SH2_SH(in4, const_vec, in5, const_vec, in4, in5); + ADDS_SH2_SH(in4, tmp4, in5, tmp5, tmp4, tmp5); + SRARI_H2_SH(tmp4, tmp5, 7); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, @@ -3894,16 +4210,16 @@ static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; @@ -3917,62 +4233,144 @@ static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + LD_SH2(src1_ptr, src2_stride, in0, in1); + ADDS_SH2_SH(in0, const_vec, in1, const_vec, in0, in1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src0_ptr, src_stride, src3, src4); - LD_SH2(src1_ptr, src2_stride, in0, in1); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); - HEVC_BI_RND_CLIP2(in0, in1, tmp0, tmp1, 7, tmp0, tmp1); + ADDS_SH2_SH(in0, tmp0, in1, tmp1, tmp0, tmp1); + SRARI_H2_SH(tmp0, tmp1, 7); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst, dst_stride); +} - dst0_r = (v4i32) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(dst0_r, dst, dst_stride); +static void hevc_hv_bi_4t_8multx4_msa(uint8_t *src0_ptr, + int32_t src_stride, + int16_t *src1_ptr, + int32_t src2_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t width8mult) +{ + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v8i16 in0, in1, in2, in3; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + for (cnt = width8mult; cnt--;) { + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += 8; + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, @@ -3982,17 +4380,18 @@ static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 in0, in1, in2, in3, in4, in5; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; @@ -4008,120 +4407,87 @@ static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + src0_ptr += (5 * src_stride); + LD_SB4(src0_ptr, src_stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, const_vec, + in0, in1, in2, in3); + ADDS_SH2_SH(in4, const_vec, in5, const_vec, in4, in5); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src0_ptr, src_stride, src3, src4); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - tmp0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - tmp1 = __msa_pckev_h((v8i16) dst1_l, (v8i16) dst1_r); - - LD_SB2(src0_ptr, src_stride, src5, src6); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src6); - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - tmp2 = __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - tmp3 = __msa_pckev_h((v8i16) dst3_l, (v8i16) dst3_r); - - LD_SB2(src0_ptr, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - - dst4_r >>= 6; - dst4_l >>= 6; - tmp4 = __msa_pckev_h((v8i16) dst4_l, (v8i16) dst4_r); - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; - tmp5 = __msa_pckev_h((v8i16) dst5_l, (v8i16) dst5_r); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP2(in4, in5, tmp4, tmp5, 7, tmp4, tmp5); - - PCKEV_B2_SW(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - dst2_r = (v4i32) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, + tmp0, tmp1, tmp2, tmp3); + PCKEV_H2_SH(dst4_l, dst4_r, dst5_l, dst5_r, tmp4, tmp5); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + ADDS_SH2_SH(in4, tmp4, in5, tmp5, tmp4, tmp5); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + SRARI_H2_SH(tmp4, tmp5, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, @@ -4139,19 +4505,21 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst54_r, dst54_l, dst65_r, dst65_l, dst6; src0_ptr -= (src_stride + 1); @@ -4159,10 +4527,9 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4181,12 +4548,10 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); @@ -4198,55 +4563,50 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, src1_ptr_tmp += (4 * src2_stride); XORI_B4_128_SB(src3, src4, src5, src6); + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, - tmp0, tmp1, tmp2, tmp3); - - PCKEV_B2_SW(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst_tmp, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src0_ptr += 8; @@ -4267,10 +4627,13 @@ static void hevc_hv_bi_4t_8w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hv_bi_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); + } else if (4 == height) { + hevc_hv_bi_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + dst, dst_stride, filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_bi_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); } else { hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -4289,11 +4652,196 @@ static void hevc_hv_bi_4t_12w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, 8); - hevc_hv_bi_4t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, height); + uint32_t loop_cnt; + uint64_t tp0, tp1; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, const_vec; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + src0_ptr_tmp = src0_ptr; + dst_tmp = dst; + src1_ptr_tmp = src1_ptr; + + LD_SB3(src0_ptr_tmp, src_stride, src0, src1, src2); + src0_ptr_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr_tmp, src_stride, src3, src4, src5, src6); + src0_ptr_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); + src1_ptr_tmp += (4 * src2_stride); + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src0_ptr += 8; + dst += 8; + src1_ptr += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src0_ptr, src_stride, src0, src1, src2); + src0_ptr += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src0_ptr, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src0_ptr += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_bi_4t_16w_msa(uint8_t *src0_ptr, @@ -4306,9 +4854,14 @@ static void hevc_hv_bi_4t_16w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, 16); + if (4 == height) { + hevc_hv_bi_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + dst, dst_stride, filter_x, filter_y, 2); + } else { + hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, filter_x, + filter_y, height, 16); + } } static void hevc_hv_bi_4t_24w_msa(uint8_t *src0_ptr, @@ -4333,7 +4886,7 @@ static void hevc_hv_bi_4t_32w_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const const int8_t *filter_y, + const int8_t *filter_y, int32_t height) { hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -4368,22 +4921,22 @@ BI_MC_COPY(64); #undef BI_MC_COPY -#define BI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ -void ff_hevc_put_hevc_bi_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t dst_stride, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int16_t *src_16bit, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ - \ - hevc_##DIR1##_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ - MAX_PB_SIZE, dst, dst_stride, \ - filter, height); \ +#define BI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ +void ff_hevc_put_hevc_bi_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src_16bit, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ + \ + hevc_##DIR1##_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter, height); \ } BI_MC(qpel, h, 4, 8, hz, mx); @@ -4422,41 +4975,40 @@ BI_MC(epel, v, 32, 4, vt, my); #undef BI_MC -#define BI_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_bi_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t dst_stride, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int16_t *src_16bit, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - hevc_##DIR1##_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ - MAX_PB_SIZE, dst, dst_stride, \ - filter_x, filter_y, \ - height); \ +#define BI_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_bi_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src_16bit, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + \ + hevc_hv_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter_x, filter_y, height); \ } -BI_MC_HV(qpel, hv, 4, 8, hv); -BI_MC_HV(qpel, hv, 8, 8, hv); -BI_MC_HV(qpel, hv, 12, 8, hv); -BI_MC_HV(qpel, hv, 16, 8, hv); -BI_MC_HV(qpel, hv, 24, 8, hv); -BI_MC_HV(qpel, hv, 32, 8, hv); -BI_MC_HV(qpel, hv, 48, 8, hv); -BI_MC_HV(qpel, hv, 64, 8, hv); +BI_MC_HV(qpel, 4, 8); +BI_MC_HV(qpel, 8, 8); +BI_MC_HV(qpel, 12, 8); +BI_MC_HV(qpel, 16, 8); +BI_MC_HV(qpel, 24, 8); +BI_MC_HV(qpel, 32, 8); +BI_MC_HV(qpel, 48, 8); +BI_MC_HV(qpel, 64, 8); -BI_MC_HV(epel, hv, 4, 4, hv); -BI_MC_HV(epel, hv, 8, 4, hv); -BI_MC_HV(epel, hv, 6, 4, hv); -BI_MC_HV(epel, hv, 12, 4, hv); -BI_MC_HV(epel, hv, 16, 4, hv); -BI_MC_HV(epel, hv, 24, 4, hv); -BI_MC_HV(epel, hv, 32, 4, hv); +BI_MC_HV(epel, 4, 4); +BI_MC_HV(epel, 8, 4); +BI_MC_HV(epel, 6, 4); +BI_MC_HV(epel, 12, 4); +BI_MC_HV(epel, 16, 4); +BI_MC_HV(epel, 24, 4); +BI_MC_HV(epel, 32, 4); #undef BI_MC_HV diff --git a/libavcodec/mips/hevc_mc_biw_msa.c b/libavcodec/mips/hevc_mc_biw_msa.c index 05a28ece4..ea65f0049 100644 --- a/libavcodec/mips/hevc_mc_biw_msa.c +++ b/libavcodec/mips/hevc_mc_biw_msa.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) + * Copyright (c) 2015 - 2017 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) * * This file is part of FFmpeg. * @@ -22,9 +22,17 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 +}; + #define HEVC_BIW_RND_CLIP2(in0, in1, vec0, vec1, wgt, rnd, offset, \ - out0_r, out1_r, out0_l, out1_l) \ + out0, out1) \ { \ + v4i32 out0_r, out1_r, out0_l, out1_l; \ + \ ILVR_H2_SW(in0, vec0, in1, vec1, out0_r, out1_r); \ ILVL_H2_SW(in0, vec0, in1, vec1, out0_l, out1_l); \ \ @@ -34,37 +42,41 @@ out1_l = __msa_dpadd_s_w(offset, (v8i16) out1_l, (v8i16) wgt); \ \ SRAR_W4_SW(out0_r, out1_r, out0_l, out1_l, rnd); \ - \ - out0_r = CLIP_SW_0_255(out0_r); \ - out1_r = CLIP_SW_0_255(out1_r); \ - out0_l = CLIP_SW_0_255(out0_l); \ - out1_l = CLIP_SW_0_255(out1_l); \ + PCKEV_H2_SH(out0_l, out0_r, out1_l, out1_r, out0, out1); \ + CLIP_SH2_0_255(out0, out1); \ } -#define HEVC_BIW_RND_CLIP4(in0, in1, in2, in3, vec0, vec1, vec2, vec3, \ - wgt, rnd, offset, \ - out0_r, out1_r, out2_r, out3_r, \ - out0_l, out1_l, out2_l, out3_l) \ -{ \ - HEVC_BIW_RND_CLIP2(in0, in1, vec0, vec1, wgt, rnd, offset, \ - out0_r, out1_r, out0_l, out1_l) \ - HEVC_BIW_RND_CLIP2(in2, in3, vec2, vec3, wgt, rnd, offset, \ - out2_r, out3_r, out2_l, out3_l) \ +#define HEVC_BIW_RND_CLIP4(in0, in1, in2, in3, vec0, vec1, vec2, vec3, \ + wgt, rnd, offset, out0, out1, out2, out3) \ +{ \ + HEVC_BIW_RND_CLIP2(in0, in1, vec0, vec1, wgt, rnd, offset, out0, out1); \ + HEVC_BIW_RND_CLIP2(in2, in3, vec2, vec3, wgt, rnd, offset, out2, out3); \ } -#define HEVC_BI_RND_CLIP2(in0, in1, vec0, vec1, rnd_val, out0, out1) \ -{ \ - ADDS_SH2_SH(vec0, in0, vec1, in1, out0, out1); \ - SRARI_H2_SH(out0, out1, rnd_val); \ - CLIP_SH2_0_255(out0, out1); \ +#define HEVC_BIW_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, wgt, rnd, \ + offset, out0, out1) \ +{ \ + v4i32 out0_r, out1_r, out0_l, out1_l; \ + \ + ILVR_H2_SW(in0, vec0, in1, vec1, out0_r, out1_r); \ + ILVL_H2_SW(in0, vec0, in1, vec1, out0_l, out1_l); \ + out0_r = __msa_dpadd_s_w(offset, (v8i16) out0_r, (v8i16) wgt); \ + out1_r = __msa_dpadd_s_w(offset, (v8i16) out1_r, (v8i16) wgt); \ + out0_l = __msa_dpadd_s_w(offset, (v8i16) out0_l, (v8i16) wgt); \ + out1_l = __msa_dpadd_s_w(offset, (v8i16) out1_l, (v8i16) wgt); \ + SRAR_W4_SW(out0_r, out1_r, out0_l, out1_l, rnd); \ + PCKEV_H2_SH(out0_l, out0_r, out1_l, out1_r, out0, out1); \ + CLIP_SH2_0_255_MAX_SATU(out0, out1); \ } -#define HEVC_BI_RND_CLIP4(in0, in1, in2, in3, \ - vec0, vec1, vec2, vec3, rnd_val, \ - out0, out1, out2, out3) \ -{ \ - HEVC_BI_RND_CLIP2(in0, in1, vec0, vec1, rnd_val, out0, out1); \ - HEVC_BI_RND_CLIP2(in2, in3, vec2, vec3, rnd_val, out2, out3); \ +#define HEVC_BIW_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, vec0, vec1, vec2, \ + vec3, wgt, rnd, offset, out0, out1, \ + out2, out3) \ +{ \ + HEVC_BIW_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, wgt, rnd, offset, \ + out0, out1); \ + HEVC_BIW_RND_CLIP2_MAX_SATU(in2, in3, vec2, vec3, wgt, rnd, offset, \ + out2, out3); \ } static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, @@ -80,93 +92,77 @@ static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { + uint32_t loop_cnt, tp0, tp1, tp2, tp3; + uint64_t tpd0, tpd1, tpd2, tpd3; int32_t offset, weight; + v16u8 out0, out1; v16i8 zero = { 0 }; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 src0 = { 0 }, src1 = { 0 }; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst0, dst1, dst2, dst3, weight_vec; + v4i32 dst0_r, dst0_l, offset_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); if (2 == height) { - v16i8 src0, src1; - v8i16 in0, in1, dst0; - v4i32 dst0_r, dst0_l; - - LD_SB2(src0_ptr, src_stride, src0, src1); - LD_SH2(src1_ptr, src2_stride, in0, in1); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0); + LW2(src0_ptr, src_stride, tp0, tp1); + INSERT_W2_SB(tp0, tp1, src0); + LD2(src1_ptr, src2_stride, tpd0, tpd1); + INSERT_D2_SH(tpd0, tpd1, in0); dst0 = (v8i16) __msa_ilvr_b(zero, src0); dst0 <<= 6; ILVRL_H2_SW(dst0, in0, dst0_r, dst0_l); - dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, - (v8i16) weight_vec); - dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, - (v8i16) weight_vec); + dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, weight_vec); + dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, weight_vec); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = (v8i16) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); + out0 = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); + ST4x2_UB(out0, dst, dst_stride); } else if (4 == height) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_W2_SB(src1, src0, src3, src2, src0, src1); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - dst0 <<= 6; - dst1 <<= 6; - HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst0, dst1, in0, in1, weight_vec, rnd_vec, + offset_vec, dst0, dst1); + out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == height % 8) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB8(src0_ptr, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src0_ptr += (8 * src_stride); - LD_SH8(src1_ptr, src2_stride, - in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); - ILVR_W4_SB(src1, src0, src3, src2, src5, src4, src7, src6, - src0, src1, src2, src3); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in2); + INSERT_D2_SH(tpd2, tpd3, in3); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, + in3, weight_vec, rnd_vec, offset_vec, + dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -187,11 +183,12 @@ static void hevc_biwgt_copy_6w_msa(uint8_t *src0_ptr, { uint32_t loop_cnt; int32_t offset, weight; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1; v16i8 zero = { 0 }; - v16i8 src0, src1, src2, src3; + v16i8 src0 = { 0 }, src1 = { 0 }; v8i16 in0, in1, in2, in3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -203,23 +200,21 @@ static void hevc_biwgt_copy_6w_msa(uint8_t *src0_ptr, rnd_vec = __msa_fill_w(rnd_val + 1); for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, + in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, + dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST6x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -237,8 +232,13 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { + uint64_t tp0, tp1, tp2, tp3; int32_t offset, weight; + v16u8 out0, out1, out2; v16i8 zero = { 0 }; + v16i8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }; + v8i16 in0, in1, in2, in3, in4, in5; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -250,80 +250,59 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, rnd_vec = __msa_fill_w(rnd_val + 1); if (2 == height) { - v16i8 src0, src1; - v8i16 in0, in1, dst0, dst1; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - - LD_SB2(src0_ptr, src_stride, src0, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src0); LD_SH2(src1_ptr, src2_stride, in0, in1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - - dst0 <<= 6; - dst1 <<= 6; HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out0, dst, dst_stride); } else if (6 == height) { - v16i8 src0, src1, src2, src3, src4, src5; - v8i16 in0, in1, in2, in3, in4, in5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - - LD_SB6(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src2); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - ILVR_B2_SH(zero, src4, zero, src5, dst4, dst5); - SLLI_4V(dst0, dst1, dst2, dst3, 6); - dst4 <<= 6; - dst5 <<= 6; - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + SLLI_2V(dst4, dst5, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, + offset_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } else if (0 == height % 4) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, + in3, weight_vec, rnd_vec, offset_vec, + dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -345,11 +324,10 @@ static void hevc_biwgt_copy_12w_msa(uint8_t *src0_ptr, uint32_t loop_cnt; int32_t offset, weight; v16i8 zero = { 0 }; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -377,108 +355,17 @@ static void hevc_biwgt_copy_12w_msa(uint8_t *src0_ptr, dst4 <<= 6; dst5 <<= 6; - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, + offset_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); } } -static void hevc_biwgt_copy_16multx4mult_msa(uint8_t *src0_ptr, - int32_t src_stride, - int16_t *src1_ptr, - int32_t src2_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - int32_t weight0, - int32_t weight1, - int32_t offset0, - int32_t offset1, - int32_t rnd_val, - int32_t width) -{ - uint32_t loop_cnt, cnt; - uint8_t *src0_ptr_tmp; - int16_t *src1_ptr_tmp; - uint8_t *dst_tmp; - int32_t offset, weight; - v16i8 zero = { 0 }; - v4i32 offset_vec, weight_vec, rnd_vec; - - offset = (offset0 + offset1) << rnd_val; - weight0 = weight0 & 0x0000FFFF; - weight = weight0 | (weight1 << 16); - - offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); - rnd_vec = __msa_fill_w(rnd_val + 1); - - for (cnt = (width >> 4); cnt--;) { - src0_ptr_tmp = src0_ptr; - src1_ptr_tmp = src1_ptr; - dst_tmp = dst; - - for (loop_cnt = (height >> 2); loop_cnt--;) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l; - - LD_SB4(src0_ptr_tmp, src_stride, src0, src1, src2, src3); - src0_ptr_tmp += (4 * src_stride); - LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); - LD_SH4(src1_ptr_tmp + 8, src2_stride, in4, in5, in6, in7); - src1_ptr_tmp += (4 * src2_stride); - - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - tmp0, tmp1, tmp2, tmp3); - ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - tmp4, tmp5, tmp6, tmp7); - - SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); - SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - in0, in1, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - - HEVC_BIW_RND_CLIP4(tmp2, tmp3, tmp6, tmp7, - in2, in3, in6, in7, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - } - - src0_ptr += 16; - src1_ptr += 16; - dst += 16; - } -} - static void hevc_biwgt_copy_16w_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, @@ -492,10 +379,46 @@ static void hevc_biwgt_copy_16w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 16); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3; + v16i8 zero = { 0 }; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = (height >> 2); loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + src1_ptr += (4 * src2_stride); + ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp0, tmp1, + tmp2, tmp3); + ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp4, tmp5, + tmp6, tmp7); + SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); + SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp0, tmp1, tmp4, tmp5, in0, in1, in4, in5, + weight_vec, rnd_vec, offset_vec, tmp0, tmp1, + tmp4, tmp5); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp2, tmp3, tmp6, tmp7, in2, in3, in6, in7, + weight_vec, rnd_vec, offset_vec, tmp2, tmp3, + tmp6, tmp7); + PCKEV_B2_UB(tmp4, tmp0, tmp5, tmp1, out0, out1); + PCKEV_B2_UB(tmp6, tmp2, tmp7, tmp3, out2, out3); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_biwgt_copy_24w_msa(uint8_t *src0_ptr, @@ -511,14 +434,55 @@ static void hevc_biwgt_copy_24w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 16); - hevc_biwgt_copy_8w_msa(src0_ptr + 16, src_stride, - src1_ptr + 16, src2_stride, - dst + 16, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, dst11; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src4, src5); + LD_SB4(src0_ptr + 16, src_stride, src2, src3, src6, src7); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + LD_SH4(src1_ptr + 16, src2_stride, in8, in9, in10, in11); + src1_ptr += (4 * src2_stride); + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVR_B2_SH(zero, src2, zero, src3, dst4, dst5); + ILVRL_B2_SH(zero, src4, dst6, dst7); + ILVRL_B2_SH(zero, src5, dst8, dst9); + ILVR_B2_SH(zero, src6, zero, src7, dst10, dst11); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + SLLI_4V(dst8, dst9, dst10, dst11, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in4, in1, in5, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst4, dst5, dst6, dst7, in8, in9, in2, in6, + weight_vec, rnd_vec, offset_vec, dst4, dst5, + dst6, dst7); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst8, dst9, dst10, dst11, in3, in7, in10, + in11, weight_vec, rnd_vec, offset_vec, + dst8, dst9, dst10, dst11); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST_UB4(out0, out1, out3, out4, dst, dst_stride); + ST8x4_UB(out2, out5, dst + 16, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_biwgt_copy_32w_msa(uint8_t *src0_ptr, @@ -534,10 +498,52 @@ static void hevc_biwgt_copy_32w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 32); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3; + v16i8 zero = { 0 }; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SB2(src0_ptr, 16, src2, src3); + src0_ptr += src_stride; + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + src1_ptr += src2_stride; + LD_SH4(src1_ptr, 8, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, tmp0, tmp4); + ILVRL_B2_SH(zero, src1, tmp1, tmp5); + ILVRL_B2_SH(zero, src2, tmp2, tmp6); + ILVRL_B2_SH(zero, src3, tmp3, tmp7); + SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); + SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp0, tmp4, tmp1, tmp5, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, tmp0, tmp4, + tmp1, tmp5); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp2, tmp6, tmp3, tmp7, in4, in5, in6, in7, + weight_vec, rnd_vec, offset_vec, tmp2, tmp6, + tmp3, tmp7); + PCKEV_B2_UB(tmp4, tmp0, tmp5, tmp1, out0, out1); + PCKEV_B2_UB(tmp6, tmp2, tmp7, tmp3, out2, out3); + ST_UB2(out0, out1, dst, 16); + dst += dst_stride; + ST_UB2(out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_biwgt_copy_48w_msa(uint8_t *src0_ptr, @@ -553,10 +559,43 @@ static void hevc_biwgt_copy_48w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 48); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, in0, in1, in2, in3, in4, in5; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = 64; loop_cnt--;) { + LD_SB3(src0_ptr, 16, src0, src1, src2); + src0_ptr += src_stride; + LD_SH6(src1_ptr, 8, in0, in1, in2, in3, in4, in5); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_2V(dst4, dst5, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, + offset_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST_UB2(out0, out1, dst, 16); + ST_UB(out2, dst + 32); + dst += dst_stride; + } } static void hevc_biwgt_copy_64w_msa(uint8_t *src0_ptr, @@ -572,10 +611,46 @@ static void hevc_biwgt_copy_64w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 64); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3; + v16i8 zero = { 0 }; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = height; loop_cnt--;) { + LD_SB4(src0_ptr, 16, src0, src1, src2, src3); + src0_ptr += src_stride; + LD_SH8(src1_ptr, 8, in0, in1, in2, in3, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp0, tmp1, + tmp2, tmp3); + ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp4, tmp5, + tmp6, tmp7); + SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); + SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp0, tmp4, tmp1, tmp5, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, tmp0, tmp4, + tmp1, tmp5); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp2, tmp6, tmp3, tmp7, in4, in5, in6, in7, + weight_vec, rnd_vec, offset_vec, tmp2, tmp6, + tmp3, tmp7); + PCKEV_B2_UB(tmp4, tmp0, tmp5, tmp1, out0, out1); + PCKEV_B2_UB(tmp6, tmp2, tmp7, tmp3, out2, out3); + ST_UB4(out0, out1, out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, @@ -593,17 +668,16 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1, filt2, filt3; v16i8 src0, src1, src2, src3; v16i8 mask1, mask2, mask3; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1; v8i16 in0, in1, in2, in3; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out0, out1; v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src0_ptr -= 3; filter_vec = LD_SH(filter); @@ -616,9 +690,10 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -633,21 +708,19 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -667,25 +740,25 @@ static void hevc_hz_biwgt_8t_8w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1, filt2, filt3; v16i8 src0, src1, src2, src3; v16i8 mask1, mask2, mask3; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l, dst2_r, dst3_r, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -706,34 +779,28 @@ static void hevc_hz_biwgt_8t_8w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -752,12 +819,85 @@ static void hevc_hz_biwgt_8t_12w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hz_biwgt_8t_8w_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, - weight0, weight1, offset0, offset1, rnd_val); - hevc_hz_biwgt_8t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter, height, - weight0, weight1, offset0, offset1, rnd_val); + uint32_t loop_cnt; + int32_t offset, weight, constant; + v16i8 src0, src1, src2, src3, vec0, vec1, vec2, vec3; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v8i16 filt0, filt1, filt2, filt3, out0, out1, out2, out3; + v8i16 dst0, dst1, dst2, dst3, in0, in1, in2, in3, filter_vec; + v4i32 weight_vec, offset_vec, rnd_vec; + + src0_ptr -= 3; + + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset = (offset0 + offset1) << rnd_val; + offset += constant; + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + filter_vec = LD_SH(filter); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + mask0 = LD_SB(&ff_hevc_mask_arr[0]); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + mask4 = LD_SB(&ff_hevc_mask_arr[16]); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, out0, out1, out2, + out3); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + + LD_SB4(src0_ptr + 8, src_stride, src0, src1, src2, src3); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr + 8, src2_stride, in0, in1, in2, in3); + src1_ptr += (4 * src2_stride); + ILVR_D2_SH(in1, in0, in3, in2, in0, in1); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src2, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, + offset_vec, out0, out1); + out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst + 8, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, @@ -775,15 +915,14 @@ static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out0, out1, out2, out3; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; v4i32 weight_vec, offset_vec, rnd_vec; v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; @@ -791,9 +930,10 @@ static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -818,34 +958,28 @@ static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -866,25 +1000,26 @@ static void hevc_hz_biwgt_8t_24w_msa(uint8_t *src0_ptr, { uint32_t loop_cnt; uint64_t dst_val0; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1; v8i16 in0, in1, in2; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2; - v4i32 dst0_r, dst1_r, dst2_r, dst0_l, dst1_l, dst2_l; - v8i16 filter_vec, const_vec; + v4i32 dst2_r, dst2_l; + v8i16 filter_vec, out0, out1, out2; v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr = src0_ptr - 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -900,33 +1035,30 @@ static void hevc_hz_biwgt_8t_24w_msa(uint8_t *src0_ptr, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB2(src0_ptr, 16, src0, src1); - src0_ptr += src_stride; - LD_SH2(src1_ptr, 8, in0, in1); - in2 = LD_SH(src1_ptr + 16); - src1_ptr += src2_stride; - XORI_B2_128_SB(src0, src1); + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SH2(src1_ptr, 8, in0, in1); + in2 = LD_SH(src1_ptr + 16); + src1_ptr += src2_stride; + XORI_B2_128_SB(src0, src1); + for (loop_cnt = 31; loop_cnt--;) { VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1); ILVRL_H2_SW(dst2, in2, dst2_r, dst2_l); dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, @@ -934,16 +1066,44 @@ static void hevc_hz_biwgt_8t_24w_msa(uint8_t *src0_ptr, dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, (v8i16) weight_vec); SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); - dst2_r = CLIP_SW_0_255(dst2_r); - dst2_l = CLIP_SW_0_255(dst2_l); + dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); + out2 = CLIP_SH_0_255(dst2_r); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - HEVC_PCK_SW_SB2(dst2_l, dst2_r, dst2_r); - dst_val0 = __msa_copy_u_d((v2i64) dst2_r, 0); - ST_SW(dst0_r, dst); + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SH2(src1_ptr, 8, in0, in1); + in2 = LD_SH(src1_ptr + 16); + src1_ptr += src2_stride; + XORI_B2_128_SB(src0, src1); + PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); + dst_val0 = __msa_copy_u_d((v2i64) out2, 0); + ST_SH(out0, dst); SD(dst_val0, dst + 16); dst += dst_stride; } + + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, + out0, out1); + ILVRL_H2_SW(dst2, in2, dst2_r, dst2_l); + dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, (v8i16) weight_vec); + dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, (v8i16) weight_vec); + SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); + dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); + out2 = CLIP_SH_0_255(dst2_r); + PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); + dst_val0 = __msa_copy_u_d((v2i64) out2, 0); + ST_SH(out0, dst); + SD(dst_val0, dst + 16); + dst += dst_stride; } static void hevc_hz_biwgt_8t_32w_msa(uint8_t *src0_ptr, @@ -961,25 +1121,25 @@ static void hevc_hz_biwgt_8t_32w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -1006,34 +1166,28 @@ static void hevc_hz_biwgt_8t_32w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst, 16); dst += dst_stride; } } @@ -1053,27 +1207,25 @@ static void hevc_hz_biwgt_8t_48w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; - uint64_t dst_val0; - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3, in4, in5; + int32_t offset, weight, constant; + v16i8 src0, src1, src2, src3, src4; + v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -1089,86 +1241,57 @@ static void hevc_hz_biwgt_8t_48w_msa(uint8_t *src0_ptr, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB3(src0_ptr, 16, src0, src1, src2); - src3 = LD_SB(src0_ptr + 40); + for (loop_cnt = 64; loop_cnt--;) { + LD_SB2(src0_ptr, 16, src0, src1); + src2 = LD_SB(src0_ptr + 24); + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + XORI_B3_128_SB(src0, src1, src2); + LD_SB2(src0_ptr + 32, 8, src3, src4); src0_ptr += src_stride; - LD_SH2(src1_ptr, 8, in0, in1); - in2 = LD_SH(src1_ptr + 16); - XORI_B4_128_SB(src0, src1, src2, src3); + XORI_B2_128_SB(src3, src4); VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src1, src2, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); - HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, + HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1, out2, out3); - ILVRL_H2_SW(dst2, in2, dst2_r, dst2_l); - dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, - (v8i16) weight_vec); - dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, - (v8i16) weight_vec); - SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); - dst2_r = CLIP_SW_0_255(dst2_r); - dst2_l = CLIP_SW_0_255(dst2_l); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst, 16); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - HEVC_PCK_SW_SB2(dst2_l, dst2_r, dst2_r); - dst_val0 = __msa_copy_u_d((v2i64) dst2_r, 0); - ST_SW(dst0_r, dst); - SD(dst_val0, dst + 16); - - LD_SH2(src1_ptr + 24, 8, in3, in4); - in5 = LD_SH(src1_ptr + 40); + LD_SH2(src1_ptr + 32, 8, in2, in3); src1_ptr += src2_stride; - HEVC_BIW_RND_CLIP2(dst3, dst4, in3, in4, + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, + vec0, vec1, vec2, vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, + vec0, vec1, vec2, vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + HEVC_BIW_RND_CLIP2(dst0, dst1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst3_r, dst4_r, dst3_l, dst4_l); + out0, out1); - ILVRL_H2_SW(dst5, in5, dst5_r, dst5_l); - dst5_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst5_r, - (v8i16) weight_vec); - dst5_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst5_l, - (v8i16) weight_vec); - SRAR_W2_SW(dst5_r, dst5_l, rnd_vec); - dst5_r = CLIP_SW_0_255(dst5_r); - dst5_l = CLIP_SW_0_255(dst5_l); - - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - HEVC_PCK_SW_SB2(dst3_l, dst3_r, dst3_r); - dst_val0 = __msa_copy_u_d((v2i64) dst3_r, 0); - SD(dst_val0, dst + 24); - ST_SW(dst4_r, dst + 32); + out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST_SH(out0, dst + 32); dst += dst_stride; } } @@ -1191,25 +1314,25 @@ static void hevc_hz_biwgt_8t_64w_msa(uint8_t *src0_ptr, uint8_t *dst_tmp; int16_t *src1_ptr_tmp; uint32_t loop_cnt, cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -1240,34 +1363,28 @@ static void hevc_hz_biwgt_8t_64w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, 16); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst_tmp, 16); dst_tmp += 32; } @@ -1303,22 +1420,22 @@ static void hevc_vt_biwgt_8t_4w_msa(uint8_t *src0_ptr, v16i8 src2110, src4332, src6554, src8776, src10998; v16i8 src12111110, src14131312; v8i16 dst10, dst32, dst54, dst76; - v4i32 dst10_r, dst32_r, dst54_r, dst76_r; - v4i32 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, out0, out1, out2, out3; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1351,28 +1468,22 @@ static void hevc_vt_biwgt_8t_4w_msa(uint8_t *src0_ptr, src8776, src10998, src12111110, src14131312); XORI_B4_128_SB(src8776, src10998, src12111110, src14131312); - dst10 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, filt0, filt1, - filt2, filt3, dst10, dst10, dst10, dst10); - dst32 = const_vec; - DPADD_SB4_SH(src4332, src6554, src8776, src10998, - filt0, filt1, filt2, filt3, dst32, dst32, dst32, dst32); - dst54 = const_vec; - DPADD_SB4_SH(src6554, src8776, src10998, src12111110, - filt0, filt1, filt2, filt3, dst54, dst54, dst54, dst54); - dst76 = const_vec; - DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, - filt0, filt1, filt2, filt3, dst76, dst76, dst76, dst76); + DOTP_SB4_SH(src2110, src4332, src6554, src8776, filt0, filt0, filt0, + filt0, dst10, dst32, dst54, dst76); + DPADD_SB4_SH(src4332, src6554, src8776, src10998, filt1, filt1, filt1, + filt1, dst10, dst32, dst54, dst76); + DPADD_SB4_SH(src6554, src8776, src10998, src12111110, filt2, filt2, + filt2, filt2, dst10, dst32, dst54, dst76); + DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, filt3, filt3, + filt3, filt3, dst10, dst32, dst54, dst76); HEVC_BIW_RND_CLIP4(dst10, dst32, dst54, dst76, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst10_r, dst32_r, dst54_r, dst76_r, - dst10_l, dst32_l, dst54_l, dst76_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst10_l, dst10_r, dst32_l, dst32_r, - dst54_l, dst54_r, dst76_l, dst76_r, dst10_r, dst54_r); - ST4x8_UB(dst10_r, dst54_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1405,20 +1516,21 @@ static void hevc_vt_biwgt_8t_8w_msa(uint8_t *src0_ptr, v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, out0, out1, out2, out3; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1441,28 +1553,22 @@ static void hevc_vt_biwgt_8t_8w_msa(uint8_t *src0_ptr, ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); + DOTP_SB4_SH(src10_r, src21_r, src32_r, src43_r, filt0, filt0, filt0, + filt0, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src32_r, src43_r, src54_r, src65_r, filt1, filt1, filt1, + filt1, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src54_r, src65_r, src76_r, src87_r, filt2, filt2, filt2, + filt2, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src76_r, src87_r, src98_r, src109_r, filt3, filt3, filt3, + filt3, tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1500,20 +1606,22 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, v16i8 src21_l, src43_l, src65_l, src87_l; v16i8 src2110, src4332, src6554, src8776; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst0_l, dst1_l, dst2_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 out0, out1, out2, filter_vec; + v4i32 dst2_r, dst2_l; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1531,7 +1639,7 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, ILVR_D3_SB(src21_l, src10_l, src43_l, src32_l, src65_l, src54_l, src2110, src4332, src6554); - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = 8; loop_cnt--;) { LD_SB2(src0_ptr, src_stride, src7, src8); src0_ptr += (2 * src_stride); LD_SH2(src1_ptr, src2_stride, in0, in1); @@ -1544,19 +1652,18 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); src8776 = (v16i8) __msa_ilvr_d((v2i64) src87_l, (v2i64) src76_l); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); + DOTP_SB3_SH(src10_r, src21_r, src2110, filt0, filt0, filt0, + tmp0, tmp1, tmp2); + DPADD_SB2_SH(src32_r, src43_r, filt1, filt1, tmp0, tmp1); + tmp2 = __msa_dpadd_s_h(tmp2, src4332, (v16i8) filt1); + DPADD_SB2_SH(src54_r, src65_r, filt2, filt2, tmp0, tmp1); + tmp2 = __msa_dpadd_s_h(tmp2, src6554, (v16i8) filt2); + DPADD_SB2_SH(src76_r, src87_r, filt3, filt3, tmp0, tmp1); + tmp2 = __msa_dpadd_s_h(tmp2, src8776, (v16i8) filt3); HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1); ILVRL_H2_SW(tmp2, in2, dst2_r, dst2_l); dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, @@ -1564,13 +1671,11 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, (v8i16) weight_vec); SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); - dst2_r = CLIP_SW_0_255(dst2_r); - dst2_l = CLIP_SW_0_255(dst2_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - HEVC_PCK_SW_SB2(dst2_l, dst2_r, dst2_r); - ST8x2_UB(dst0_r, dst, dst_stride); - ST4x2_UB(dst2_r, dst + 8, dst_stride); + dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); + out2 = CLIP_SH_0_255(dst2_r); + PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); + ST8x2_UB(out0, dst, dst_stride); + ST4x2_UB(out2, dst + 8, dst_stride); dst += (2 * dst_stride); src10_r = src32_r; @@ -1614,9 +1719,9 @@ static void hevc_vt_biwgt_8t_16multx2mult_msa(uint8_t *src0_ptr, v16i8 src21_l, src43_l, src65_l, src87_l; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec; + v8i16 out0, out1, out2, out3; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); @@ -1624,11 +1729,13 @@ static void hevc_vt_biwgt_8t_16multx2mult_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1661,28 +1768,22 @@ static void hevc_vt_biwgt_8t_16multx2mult_msa(uint8_t *src0_ptr, ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src10_l, src32_l, src54_l, src76_l, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src21_l, src43_l, src65_l, src87_l, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); + DOTP_SB4_SH(src10_r, src21_r, src10_l, src21_l, filt0, filt0, + filt0, filt0, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src32_r, src43_r, src32_l, src43_l, filt1, filt1, + filt1, filt1, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src54_r, src65_r, src54_l, src65_l, filt2, filt2, + filt2, filt2, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src76_r, src87_r, src76_l, src87_l, filt3, filt3, + filt3, filt3, tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); + PCKEV_B2_SH(out2, out0, out3, out1, out0, out1); + ST_SH2(out0, out1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); src10_r = src32_r; @@ -1831,23 +1932,23 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v8i16 in0, in1; + uint64_t tp0, tp1; + int32_t offset, weight; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v8i16 in0 = { 0 }, in1 = { 0 }; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, weight_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r; - v4i32 tmp1, tmp2; - v4i32 weight_vec0, weight_vec1, offset_vec, rnd_vec; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 dst10, dst32, dst54, dst76; + v8i16 dst21, dst43, dst65, dst97, dst108, dst109, dst98; + v4i32 offset_vec, rnd_vec, const_vec, dst0, dst1, dst2, dst3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src0_ptr -= ((3 * src_stride) + 3); @@ -1855,10 +1956,9 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1866,13 +1966,14 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec0 = __msa_fill_w(weight0); - weight_vec1 = __msa_fill_w(weight1); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); src0_ptr += (7 * src_stride); @@ -1886,70 +1987,77 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src0_ptr, src_stride, src7, src8); - src0_ptr += (2 * src_stride); - LD_SH2(src1_ptr, src2_stride, in0, in1); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); src1_ptr += (2 * src2_stride); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src7, src8); - - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); - dst0_r >>= 6; - dst1_r >>= 6; + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); - ILVRL_H2_SW(in0, in0, tmp1, tmp2); - tmp1 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp1, (v8i16) weight_vec0); - tmp2 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp2, (v8i16) weight_vec0); - tmp1 += dst0_r * weight_vec1; - tmp2 += dst1_r * weight_vec1; - SRAR_W2_SW(tmp1, tmp2, rnd_vec); - tmp1 = CLIP_SW_0_255(tmp1); - tmp2 = CLIP_SW_0_255(tmp2); + dst0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + dst2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst0, dst1, dst2, dst3); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - HEVC_PCK_SW_SB2(tmp2, tmp1, tmp1); - ST4x2_UB(tmp1, dst, dst_stride); - dst += (2 * dst_stride); - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } @@ -1967,57 +2075,58 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, int32_t offset0, int32_t offset1, int32_t rnd_val, - int32_t width) + int32_t width8mult) { uint32_t loop_cnt, cnt; - int32_t offset; + int32_t offset, weight; uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 in0, in1; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, weight_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; - v4i32 tmp0, tmp1, tmp2, tmp3; + v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; v8i16 dst21_l, dst43_l, dst65_l, dst87_l; - v4i32 weight_vec0, weight_vec1, offset_vec, rnd_vec; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= ((3 * src_stride) + 3); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec0 = __msa_fill_w(weight0); - weight_vec1 = __msa_fill_w(weight1); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; mask3 = mask0 + 6; - for (cnt = width >> 3; cnt--;) { + for (cnt = width8mult; cnt--;) { src0_ptr_tmp = src0_ptr; src1_ptr_tmp = src1_ptr; dst_tmp = dst; @@ -2038,18 +2147,14 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); /* row 4 row 5 row 6 */ VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, @@ -2059,22 +2164,12 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); for (loop_cnt = height >> 1; loop_cnt--;) { LD_SB2(src0_ptr_tmp, src_stride, src7, src8); @@ -2084,11 +2179,17 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr_tmp, src2_stride, in0, in1); src1_ptr_tmp += (2 * src2_stride); + ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_r, + dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_l, + dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); + ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, @@ -2102,10 +2203,8 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, /* row 8 */ VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, @@ -2116,43 +2215,26 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, dst1_r >>= 6; dst1_l >>= 6; - ILVRL_H2_SW(in0, in0, tmp0, tmp1); - ILVRL_H2_SW(in1, in1, tmp2, tmp3); - tmp0 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp0, - (v8i16) weight_vec0); - tmp1 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp1, - (v8i16) weight_vec0); - tmp2 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp2, - (v8i16) weight_vec0); - tmp3 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp3, - (v8i16) weight_vec0); - - tmp0 += (dst0_r * weight_vec1); - tmp1 += (dst0_l * weight_vec1); - tmp2 += (dst1_r * weight_vec1); - tmp3 += (dst1_l * weight_vec1); - - SRAR_W4_SW(tmp0, tmp1, tmp2, tmp3, rnd_vec); - tmp0 = CLIP_SW_0_255(tmp0); - tmp1 = CLIP_SW_0_255(tmp1); - tmp2 = CLIP_SW_0_255(tmp2); - tmp3 = CLIP_SW_0_255(tmp3); - HEVC_PCK_SW_SB4(tmp1, tmp0, tmp3, tmp2, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0_r = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst0_l = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst1_r = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst1_l = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0_l, dst0_r, dst1_l, dst1_r, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst0_l, dst0_r, dst1_l, dst1_r); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; + dst0 = dst2; + dst1 = dst3; + dst2 = dst4; + dst3 = dst5; + dst4 = dst6; + dst5 = dst7; dst6 = dst8; } @@ -2181,7 +2263,7 @@ static void hevc_hv_biwgt_8t_8w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 8); + offset1, rnd_val, 1); } static void hevc_hv_biwgt_8t_12w_msa(uint8_t *src0_ptr, @@ -2199,16 +2281,239 @@ static void hevc_hv_biwgt_8t_12w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hv_biwgt_8t_8multx2mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, - offset1, rnd_val, 8); - hevc_hv_biwgt_8t_4w_msa(src0_ptr + 8, src_stride, - src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + uint32_t loop_cnt; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + int32_t offset, weight; + uint64_t tp0, tp1; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v8i16 in0 = { 0 }, in1 = { 0 }; + v8i16 filter_vec, weight_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst76_l, dst21_l, dst43_l, dst65_l; + v8i16 dst30, dst41, dst52, dst63, dst66, dst87, dst10, dst32, dst54, dst76; + v8i16 dst21, dst43, dst65, dst97, dst108, dst109, dst98, dst87_r, dst87_l; + v4i32 offset_vec, rnd_vec, const_vec, dst0, dst1, dst2, dst3; + + src0_ptr -= ((3 * src_stride) + 3); + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + const_vec = __msa_fill_w((128 * weight1)); + const_vec <<= 6; + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src0_ptr_tmp = src0_ptr; + src1_ptr_tmp = src1_ptr; + dst_tmp = dst; + + LD_SB7(src0_ptr_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dsth0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dsth1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dsth2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dsth3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dsth4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dsth5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dsth6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB2(src0_ptr_tmp, src_stride, src7, src8); + src0_ptr_tmp += (2 * src_stride); + XORI_B2_128_SB(src7, src8); + + LD_SH2(src1_ptr_tmp, src2_stride, in0, in1); + src1_ptr_tmp += (2 * src2_stride); + + ILVR_H4_SH(dsth1, dsth0, dsth3, dsth2, dsth5, dsth4, dsth2, dsth1, + dst10_r, dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dsth1, dsth0, dsth3, dsth2, dsth5, dsth4, dsth2, dsth1, + dst10_l, dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dsth4, dsth3, dsth6, dsth5, dst43_r, dst65_r); + ILVL_H2_SH(dsth4, dsth3, dsth6, dsth5, dst43_l, dst65_l); + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dsth7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + dst0 = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0 >>= 6; + dst1 >>= 6; + + VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dsth8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + dst2 = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2 >>= 6; + dst3 >>= 6; + + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst1, dst0, dst3, dst2, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst1, dst0, dst3, dst2); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst_tmp, dst_stride); + dst_tmp += (2 * dst_stride); + + dsth0 = dsth2; + dsth1 = dsth3; + dsth2 = dsth4; + dsth3 = dsth5; + dsth4 = dsth6; + dsth5 = dsth7; + dsth6 = dsth8; + } + + src0_ptr += 8; + src1_ptr += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + src1_ptr += (2 * src2_stride); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); + + dst0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + dst2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst0, dst1, dst2, dst3); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_biwgt_8t_16w_msa(uint8_t *src0_ptr, @@ -2230,7 +2535,7 @@ static void hevc_hv_biwgt_8t_16w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 16); + offset1, rnd_val, 2); } static void hevc_hv_biwgt_8t_24w_msa(uint8_t *src0_ptr, @@ -2252,7 +2557,7 @@ static void hevc_hv_biwgt_8t_24w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 24); + offset1, rnd_val, 3); } static void hevc_hv_biwgt_8t_32w_msa(uint8_t *src0_ptr, @@ -2274,7 +2579,7 @@ static void hevc_hv_biwgt_8t_32w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 32); + offset1, rnd_val, 4); } static void hevc_hv_biwgt_8t_48w_msa(uint8_t *src0_ptr, @@ -2296,7 +2601,7 @@ static void hevc_hv_biwgt_8t_48w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 48); + offset1, rnd_val, 6); } static void hevc_hv_biwgt_8t_64w_msa(uint8_t *src0_ptr, @@ -2318,7 +2623,7 @@ static void hevc_hv_biwgt_8t_64w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 64); + offset1, rnd_val, 8); } static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, @@ -2328,22 +2633,21 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1, vec0, vec1; v8i16 dst0; v4i32 dst0_r, dst0_l; - v8i16 filter_vec, const_vec; + v8i16 out0, filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2356,9 +2660,10 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2369,18 +2674,16 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); ILVRL_H2_SW(dst0, in0, dst0_r, dst0_l); dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, (v8i16) weight_vec); dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, (v8i16) weight_vec); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + out0 = CLIP_SH_0_255(dst0_r); + out0 = (v8i16) __msa_pckev_b((v16i8) out0, (v16i8) out0); + ST4x2_UB(out0, dst, dst_stride); } static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -2390,23 +2693,21 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v8i16 dst0, dst1; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2420,9 +2721,10 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2433,17 +2735,15 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, ILVR_D2_SH(in1, in0, in3, in2, in0, in1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, @@ -2461,16 +2761,15 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t weight, offset; + int32_t weight, offset, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2481,9 +2780,10 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2503,26 +2803,20 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST4x8_UB(dst0, dst1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2543,11 +2837,11 @@ static void hevc_hz_biwgt_4t_4w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hz_biwgt_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (4 == height) { hevc_hz_biwgt_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 8)) { hevc_hz_biwgt_4t_4x8multiple_msa(src0_ptr, src_stride, @@ -2573,16 +2867,15 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2593,16 +2886,17 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 2; loop_cnt--;) { LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); @@ -2610,27 +2904,21 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST6x4_UB(dst0, dst1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2642,22 +2930,20 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, vec0, vec1; v8i16 dst0, dst1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2668,9 +2954,10 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2681,17 +2968,15 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in0, in1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(dst0, dst, dst_stride); } static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -2701,24 +2986,21 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t weight, offset; + int32_t weight, offset, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3, in4, in5; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2729,9 +3011,10 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2745,38 +3028,30 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in4, in5); XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dst5 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + dst4, dst5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + dst3 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); + ST8x4_UB(dst0, dst1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(dst3, dst, dst_stride); } static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -2794,16 +3069,15 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2814,9 +3088,10 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2831,26 +3106,20 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2871,11 +3140,11 @@ static void hevc_hz_biwgt_4t_8w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hz_biwgt_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (6 == height) { hevc_hz_biwgt_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 4)) { hevc_hz_biwgt_4t_8x4multiple_msa(src0_ptr, src_stride, @@ -2901,20 +3170,18 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; v16i8 mask1, mask3; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2925,9 +3192,10 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2935,7 +3203,7 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, mask1 = mask0 + 2; mask3 = mask2 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); @@ -2945,38 +3213,29 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dst5 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + dst4, dst5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + dst3 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); + ST12x4_UB(dst0, dst1, dst3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2996,16 +3255,15 @@ static void hevc_hz_biwgt_4t_16w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -3016,9 +3274,10 @@ static void hevc_hz_biwgt_4t_16w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3035,49 +3294,37 @@ static void hevc_hz_biwgt_4t_16w_msa(uint8_t *src0_ptr, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dst5 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); + dst6 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + dst7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); dst += (2 * dst_stride); HEVC_BIW_RND_CLIP4(dst4, dst5, dst6, dst7, in4, in5, in6, in7, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -3097,17 +3344,15 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; - uint8_t *dst_tmp = dst + 16; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3, in4, in5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -3118,9 +3363,10 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3129,7 +3375,7 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = 16; loop_cnt--;) { LD_SB2(src0_ptr, src_stride, src0, src2); LD_SB2(src0_ptr + 16, src_stride, src1, src3); src0_ptr += (2 * src_stride); @@ -3140,41 +3386,33 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); + + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); /* 8 width */ VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP2(dst0, dst1, in4, in5, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(dst0, (dst + 16), dst_stride); + dst += (2 * dst_stride); } } @@ -3193,16 +3431,15 @@ static void hevc_hz_biwgt_4t_32w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; v8i16 dst0, dst1, dst2, dst3; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -3213,9 +3450,10 @@ static void hevc_hz_biwgt_4t_32w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3233,26 +3471,20 @@ static void hevc_hz_biwgt_4t_32w_msa(uint8_t *src0_ptr, XORI_B3_128_SB(src0, src1, src2); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, 16); dst += dst_stride; } } @@ -3264,20 +3496,19 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t weight, offset; + int32_t weight, offset, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, dst10; v16i8 src10_r, src32_r, src21_r, src43_r, src2110, src4332; v4i32 dst10_r, dst10_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= src_stride; @@ -3285,9 +3516,10 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3310,18 +3542,16 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + dst10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); ILVRL_H2_SW(dst10, in0, dst10_r, dst10_l); dst10_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst10_r, (v8i16) weight_vec); dst10_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst10_l, (v8i16) weight_vec); SRAR_W2_SW(dst10_r, dst10_l, rnd_vec); - dst10_r = CLIP_SW_0_255(dst10_r); - dst10_l = CLIP_SW_0_255(dst10_l); - - HEVC_PCK_SW_SB2(dst10_l, dst10_r, dst10_r); - ST4x2_UB(dst10_r, dst, dst_stride); + dst10_r = (v4i32) __msa_pckev_h((v8i16) dst10_l, (v8i16) dst10_r); + out = CLIP_SH_0_255(dst10_r); + out = (v8i16) __msa_pckev_b((v16i8) out, (v16i8) out); + ST4x2_UB(out, dst, dst_stride); } static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -3331,22 +3561,20 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t weight, offset; + int32_t weight, offset, constant; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src54_r, src21_r, src43_r, src65_r; v16i8 src2110, src4332, src6554; v8i16 dst10, dst32; - v4i32 dst10_r, dst32_r, dst10_l, dst32_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= src_stride; @@ -3354,9 +3582,10 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3380,17 +3609,15 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, ILVR_D2_SB(src43_r, src32_r, src65_r, src54_r, src4332, src6554); XORI_B2_128_SB(src4332, src6554); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + dst10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst32 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); HEVC_BIW_RND_CLIP2(dst10, dst32, in0, in1, weight_vec, rnd_vec, offset_vec, - dst10_r, dst32_r, dst10_l, dst32_l); + dst10, dst32); - HEVC_PCK_SW_SB4(dst10_l, dst10_r, dst32_l, dst32_r, dst10_r); - ST4x4_UB(dst10_r, dst10_r, 0, 1, 2, 3, dst, dst_stride); + dst10 = (v8i16) __msa_pckev_b((v16i8) dst32, (v16i8) dst10); + ST4x4_UB(dst10, dst10, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -3409,17 +3636,15 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t weight, offset; + int32_t weight, offset, constant; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; v16i8 src2110, src4332, src6554, src8776; v8i16 dst10, dst32, dst54, dst76; - v4i32 dst10_r, dst32_r, dst54_r, dst76_r; - v4i32 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= src_stride; @@ -3427,9 +3652,10 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3459,12 +3685,9 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, src4332, src6554, src8776); XORI_B3_128_SB(src4332, src6554, src8776); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - dst54 = const_vec; - DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + dst10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst32 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + dst54 = HEVC_FILT_4TAP_SH(src6554, src8776, filt0, filt1); LD_SB2(src0_ptr, src_stride, src9, src2); src0_ptr += (2 * src_stride); @@ -3472,17 +3695,14 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, src2110 = (v16i8) __msa_ilvr_d((v2i64) src109_r, (v2i64) src98_r); src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - dst76 = const_vec; - DPADD_SB2_SH(src8776, src2110, filt0, filt1, dst76, dst76); + dst76 = HEVC_FILT_4TAP_SH(src8776, src2110, filt0, filt1); HEVC_BIW_RND_CLIP4(dst10, dst32, dst54, dst76, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst10_r, dst32_r, dst54_r, dst76_r, - dst10_l, dst32_l, dst54_l, dst76_l); + dst10, dst32, dst54, dst76); - HEVC_PCK_SW_SB8(dst10_l, dst10_r, dst32_l, dst32_r, - dst54_l, dst54_r, dst76_l, dst76_r, dst10_r, dst54_r); - ST4x8_UB(dst10_r, dst54_r, dst, dst_stride); + PCKEV_B2_SH(dst32, dst10, dst76, dst54, dst10, dst32); + ST4x8_UB(dst10, dst32, dst, dst_stride); dst += (8 * dst_stride); } } @@ -3503,11 +3723,11 @@ static void hevc_vt_biwgt_4t_4w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_vt_biwgt_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (4 == height) { hevc_vt_biwgt_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 8)) { hevc_vt_biwgt_4t_4x8multiple_msa(src0_ptr, src_stride, @@ -3533,24 +3753,24 @@ static void hevc_vt_biwgt_4t_6w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3571,29 +3791,23 @@ static void hevc_vt_biwgt_4t_6w_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); LD_SB2(src0_ptr, src_stride, src1, src2); src0_ptr += (2 * src_stride); XORI_B2_128_SB(src1, src2); ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + ST6x4_UB(tmp0, tmp1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3605,30 +3819,29 @@ static void hevc_vt_biwgt_4t_8x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, tmp0, tmp1; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3646,16 +3859,14 @@ static void hevc_vt_biwgt_4t_8x2_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + tmp0, tmp1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + tmp0 = (v8i16) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(tmp0, dst, dst_stride); } static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -3665,33 +3876,31 @@ static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 in0, in1, in2, in3, in4, in5; v16i8 src10_r, src32_r, src54_r, src76_r; v16i8 src21_r, src43_r, src65_r, src87_r; v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3711,33 +3920,25 @@ static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, src32_r, src43_r, src54_r, src65_r); ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, tmp3, tmp3); - tmp4 = const_vec; - DPADD_SB2_SH(src54_r, src76_r, filt0, filt1, tmp4, tmp4); - tmp5 = const_vec; - DPADD_SB2_SH(src65_r, src87_r, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP2(tmp4, tmp5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp4, tmp5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + tmp3 = (v8i16) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST8x4_UB(tmp0, tmp1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(tmp3, dst, dst_stride); } static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -3755,24 +3956,24 @@ static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3793,29 +3994,23 @@ static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); LD_SB2(src0_ptr, src_stride, src1, src2); src0_ptr += (2 * src_stride); XORI_B2_128_SB(src1, src2); ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + ST8x4_UB(tmp0, tmp1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3836,11 +4031,11 @@ static void hevc_vt_biwgt_4t_8w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_vt_biwgt_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (6 == height) { hevc_vt_biwgt_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else { hevc_vt_biwgt_4t_8x4multiple_msa(src0_ptr, src_stride, @@ -3866,7 +4061,7 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v16i8 src10_r, src32_r, src21_r, src43_r; @@ -3874,19 +4069,18 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; v16i8 src2110, src4332; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; src0_ptr -= (1 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3914,12 +4108,9 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp4 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, tmp4, tmp4); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); LD_SB2(src0_ptr, src_stride, src5, src2); src0_ptr += (2 * src_stride); @@ -3928,26 +4119,20 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - tmp5 = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, tmp5, tmp5); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src4332, src2110, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP2(tmp4, tmp5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp4, tmp5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST12x4_UB(tmp0, tmp1, tmp2, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3967,25 +4152,25 @@ static void hevc_vt_biwgt_4t_16w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src21_r, src43_r; v16i8 src10_l, src32_l, src21_l, src43_l; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -4009,23 +4194,17 @@ static void hevc_vt_biwgt_4t_16w_msa(uint8_t *src0_ptr, ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp3, tmp3); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + ST_SH2(tmp0, tmp1, dst, dst_stride); dst += (2 * dst_stride); LD_SB2(src0_ptr, src_stride, src5, src2); src0_ptr += (2 * src_stride); @@ -4037,23 +4216,17 @@ static void hevc_vt_biwgt_4t_16w_msa(uint8_t *src0_ptr, ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); ILVL_B2_SB(src5, src4, src2, src5, src10_l, src21_l); - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp3, tmp3); + tmp0 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(src32_l, src10_l, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_l, src21_l, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + ST_SH2(tmp0, tmp1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -4073,7 +4246,7 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5; v16i8 src6, src7, src8, src9, src10, src11; v8i16 in0, in1, in2, in3, in4, in5; @@ -4082,19 +4255,18 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, v16i8 src21_r, src43_r, src87_r, src109_r; v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -4130,36 +4302,28 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src9, src10); ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); /* 16width */ - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); /* 8width */ - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); /* 16width */ HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp4, tmp5); /* 8width */ HEVC_BIW_RND_CLIP2(tmp2, tmp3, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp2, tmp3); /* 16width */ - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); + PCKEV_B2_SH(tmp4, tmp0, tmp5, tmp1, tmp0, tmp1); /* 8width */ - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); + tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp3, (v16i8) tmp2); + ST_SH2(tmp0, tmp1, dst, dst_stride); + ST8x2_UB(tmp2, dst + 16, dst_stride); dst += (2 * dst_stride); /* 16width */ @@ -4177,37 +4341,29 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src11, src8); ILVR_B2_SB(src11, src10, src8, src11, src76_r, src87_r); /* 16width */ - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src32_l, src10_l, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src43_l, src21_l, filt0, filt1); /* 8width */ - tmp2 = const_vec; - DPADD_SB2_SH(src98_r, src76_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src109_r, src87_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src98_r, src76_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src109_r, src87_r, filt0, filt1); /* 16width */ HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp4, tmp5); /* 8width */ HEVC_BIW_RND_CLIP2(tmp2, tmp3, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp2, tmp3); /* 16width */ - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); + PCKEV_B2_SH(tmp4, tmp0, tmp5, tmp1, tmp0, tmp1); /* 8width */ - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); + tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp3, (v16i8) tmp2); + ST_SH2(tmp0, tmp1, dst, dst_stride); + ST8x2_UB(tmp2, dst + 16, dst_stride); dst += (2 * dst_stride); } } @@ -4228,7 +4384,7 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, { uint32_t loop_cnt; uint8_t *dst_tmp = dst + 16; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v16i8 src10_r, src32_r, src76_r, src98_r; @@ -4237,19 +4393,18 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, v16i8 src10_l, src32_l, src76_l, src98_l; v16i8 src21_l, src43_l, src87_l, src109_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l, dst6_l, dst7_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -4279,24 +4434,18 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); /* 16width */ - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); /* 16width */ HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp4, tmp5); /* 16width */ - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp4, tmp0, tmp5, tmp1, tmp0, tmp1); + ST_SH2(tmp0, tmp1, dst, dst_stride); dst += (2 * dst_stride); src10_r = src32_r; @@ -4315,25 +4464,19 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); /* next 16width */ - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp6 = const_vec; - DPADD_SB2_SH(src76_l, src98_l, filt0, filt1, tmp6, tmp6); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); - tmp7 = const_vec; - DPADD_SB2_SH(src87_l, src109_l, filt0, filt1, tmp7, tmp7); + tmp2 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + tmp6 = HEVC_FILT_4TAP_SH(src76_l, src98_l, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + tmp7 = HEVC_FILT_4TAP_SH(src87_l, src109_l, filt0, filt1); /* next 16width */ HEVC_BIW_RND_CLIP4(tmp2, tmp3, tmp6, tmp7, in4, in5, in6, in7, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst6_r, dst7_r, - dst4_l, dst5_l, dst6_l, dst7_l); + tmp2, tmp3, tmp6, tmp7); /* next 16width */ - HEVC_PCK_SW_SB8(dst4_l, dst4_r, dst6_l, dst6_r, - dst5_l, dst5_r, dst7_l, dst7_r, dst4_r, dst5_r); - ST_SW2(dst4_r, dst5_r, dst_tmp, dst_stride); + PCKEV_B2_SH(tmp6, tmp2, tmp7, tmp3, tmp2, tmp3); + ST_SH2(tmp2, tmp3, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); src76_r = src98_r; @@ -4352,26 +4495,25 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { + uint64_t tp0, tp1; int32_t offset, weight; - v8i16 in0, in1; + v8i16 in0 = { 0 }; + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, tmp, weight_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r, dst0_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43, tmp0, tmp1; + v4i32 dst0, dst1, offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4379,10 +4521,9 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4390,56 +4531,44 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); - LD_SB2(src0_ptr, src_stride, src3, src4); - LD_SH2(src1_ptr, src2_stride, in0, in1); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src3, src4); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - ILVRL_H2_SW(dst1_r, in0, dst0_r, dst0_l); - dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, (v8i16) weight_vec); - dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, (v8i16) weight_vec); - SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + dst0 = (v4i32) __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + SRAR_W2_SW(dst0, dst1, rnd_vec); + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -4450,28 +4579,28 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { + uint64_t tp0, tp1; int32_t offset, weight; - v8i16 in0, in1, in2, in3; + v16u8 out; + v8i16 in0 = { 0 }, in1 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 tmp0, tmp1; - v4i32 dst0_l, dst1_l; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 dst30, dst41, dst52, dst63; + v8i16 dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 offset_vec, rnd_vec, const_vec; + v4i32 dst0, dst1, dst2, dst3; src0_ptr -= (src_stride + 1); @@ -4479,10 +4608,9 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4490,66 +4618,54 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - XORI_B4_128_SB(src3, src4, src5, src6); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); - HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, @@ -4568,22 +4684,24 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; + uint64_t tp0, tp1; int32_t offset, weight; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v16u8 out0, out1; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 filter_vec, weight_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst98_r, dst109_r; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4591,10 +4709,9 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4602,100 +4719,96 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; LD_SB3(src0_ptr, src_stride, src0, src1, src2); src0_ptr += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); src0_ptr += (8 * src_stride); - LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst54_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - dst65_r = __msa_ilvr_h(dst6, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - dst76_r = __msa_ilvr_h(dst7, dst6); - dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - dst87_r = __msa_ilvr_h(dst8, dst7); - dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - PCKEV_H4_SH(dst1_r, dst0_r, dst3_r, dst2_r, - dst5_r, dst4_r, dst7_r, dst6_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, dst0, dst1, + dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -4717,13 +4830,11 @@ static void hevc_hv_biwgt_4t_4w_msa(uint8_t *src0_ptr, if (2 == height) { hevc_hv_biwgt_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); } else if (4 == height) { hevc_hv_biwgt_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 8)) { hevc_hv_biwgt_4t_4multx8mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -4748,22 +4859,28 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - uint32_t loop_cnt; + uint32_t tpw0, tpw1, tpw2, tpw3; + uint64_t tp0, tp1; int32_t offset, weight; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v8i16 in0, in1, in2, in3; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 in4 = { 0 }, in5 = { 0 }; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, weight_vec; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v8i16 dst98_l, dst21_l, dst43_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 tmp0, tmp1, tmp2, tmp3; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4771,10 +4888,9 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4782,11 +4898,12 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; LD_SB3(src0_ptr, src_stride, src0, src1, src2); src0_ptr += (3 * src_stride); @@ -4795,74 +4912,120 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - XORI_B4_128_SB(src3, src4, src5, src6); + LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0, dst1); + PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst2, dst3); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr + 2 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + LD2(src1_ptr + 4 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr + 6 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in3); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + + PCKEV_H2_SW(dst1_l, dst0_l, dst3_l, dst2_l, dst4, dst5); + + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + src1_ptr += (4 * src2_stride); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in4); + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in5); + + ILVRL_H2_SH(dst4, in4, tmp0, tmp1); + ILVRL_H2_SH(dst5, in5, tmp2, tmp3); + + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp4, tmp5); + + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, @@ -4873,7 +5036,6 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, @@ -4881,20 +5043,21 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, int32_t rnd_val) { int32_t weight, offset; + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 filter_vec, weight_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v8i16 in0, in1; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v8i16 tmp0, tmp1; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4902,10 +5065,9 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4913,61 +5075,177 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + LD_SH2(src1_ptr, src2_stride, in0, in1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src0_ptr, src_stride, src3, src4); - - LD_SH2(src1_ptr, src2_stride, in0, in1); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - tmp0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - tmp1 = __msa_pckev_h((v8i16) dst1_l, (v8i16) dst1_r); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp1, tmp3); - HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + + dst0_r = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst0_l = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst1_r = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst1_l = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst, dst_stride); +} + +static void hevc_hv_biwgt_4t_8multx4_msa(uint8_t *src0_ptr, + int32_t src_stride, + int16_t *src1_ptr, + int32_t src2_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t weight0, + int32_t weight1, + int32_t offset0, + int32_t offset1, + int32_t rnd_val, + int32_t width8mult) +{ + int32_t weight, offset; + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, weight_vec; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, in0, in1, in2, in3; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; + + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + const_vec = __msa_fill_w((128 * weight1)); + const_vec <<= 6; + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); + + for (cnt = width8mult; cnt--;) { + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += 8; + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0, dst1, dst2, dst3); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -4978,7 +5256,6 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, @@ -4986,14 +5263,16 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t offset, weight; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 filter_vec, weight_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v4i32 dst4_r, dst4_l, dst5_r, dst5_l; v8i16 dst10_r, dst32_r, dst10_l, dst32_l; @@ -5001,8 +5280,9 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, v8i16 dst54_r, dst54_l, dst65_r, dst65_l; v8i16 dst76_r, dst76_l, dst87_r, dst87_l; v8i16 in0, in1, in2, in3, in4, in5; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -5010,10 +5290,9 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -5021,123 +5300,103 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + src0_ptr += (5 * src_stride); + LD_SB4(src0_ptr, src_stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dsth7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); - LD_SB2(src0_ptr, src_stride, src3, src4); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - tmp0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - tmp1 = __msa_pckev_h((v8i16) dst1_l, (v8i16) dst1_r); - - LD_SB2(src0_ptr, src_stride, src5, src6); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src6); - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - tmp2 = __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - tmp3 = __msa_pckev_h((v8i16) dst3_l, (v8i16) dst3_r); - - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - - LD_SB2(src0_ptr, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - dst4_r >>= 6; - dst4_l >>= 6; - tmp4 = __msa_pckev_h((v8i16) dst4_l, (v8i16) dst4_r); - - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; - tmp5 = __msa_pckev_h((v8i16) dst5_l, (v8i16) dst5_r); - HEVC_BIW_RND_CLIP2(tmp4, tmp5, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst2_r); - ST8x2_UB(dst2_r, dst, dst_stride); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + + PCKEV_H2_SW(dst4_l, dst4_r, dst5_l, dst5_r, dst0, dst1); + ILVRL_H2_SH(dst0, in4, tmp0, tmp1); + ILVRL_H2_SH(dst1, in5, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp4, tmp5); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST8x2_UB(out2, dst, dst_stride); } static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, @@ -5162,20 +5421,22 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filter_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 tmp0, tmp1, tmp2, tmp3; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l, weight_vec; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -5183,10 +5444,9 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -5194,11 +5454,12 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; for (cnt = width >> 3; cnt--;) { src0_ptr_tmp = src0_ptr; @@ -5212,15 +5473,12 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); for (loop_cnt = height >> 2; loop_cnt--;) { LD_SB4(src0_ptr_tmp, src_stride, src3, src4, src5, src6); @@ -5230,57 +5488,59 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src3, src4, src5, src6); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst_tmp, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0, dst1, dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; } src0_ptr += 8; @@ -5307,13 +5567,16 @@ static void hevc_hv_biwgt_4t_8w_msa(uint8_t *src0_ptr, if (2 == height) { hevc_hv_biwgt_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); + } else if (4 == height) { + hevc_hv_biwgt_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, filter_x, + filter_y, weight0, weight1, offset0, + offset1, rnd_val, 1); } else if (6 == height) { hevc_hv_biwgt_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 4)) { hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -5338,16 +5601,228 @@ static void hevc_hv_biwgt_4t_12w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, - filter_x, filter_y, height, weight0, - weight1, offset0, offset1, rnd_val, 8); + uint32_t loop_cnt; + uint64_t tp0, tp1; + int32_t offset, weight; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, weight_vec; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; - hevc_hv_biwgt_4t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, - offset1, rnd_val); + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + const_vec = __msa_fill_w((128 * weight1)); + const_vec <<= 6; + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); + + src0_ptr_tmp = src0_ptr; + dst_tmp = dst; + src1_ptr_tmp = src1_ptr; + + LD_SB3(src0_ptr_tmp, src_stride, src0, src1, src2); + src0_ptr_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr_tmp, src_stride, src3, src4, src5, src6); + src0_ptr_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); + src1_ptr_tmp += (4 * src2_stride); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0, dst1, dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src0_ptr += 8; + dst += 8; + src1_ptr += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src0_ptr, src_stride, src0, src1, src2); + src0_ptr += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + src0_ptr += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + dst0, dst1, dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_biwgt_4t_16w_msa(uint8_t *src0_ptr, @@ -5365,11 +5840,17 @@ static void hevc_hv_biwgt_4t_16w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, - filter_x, filter_y, height, weight0, - weight1, offset0, offset1, rnd_val, 16); + if (4 == height) { + hevc_hv_biwgt_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, filter_x, + filter_y, weight0, weight1, offset0, + offset1, rnd_val, 2); + } else { + hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, + filter_x, filter_y, height, weight0, + weight1, offset0, offset1, rnd_val, 16); + } } static void hevc_hv_biwgt_4t_24w_msa(uint8_t *src0_ptr, @@ -5453,35 +5934,32 @@ BI_W_MC_COPY(64); #undef BI_W_MC_COPY -#define BI_W_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ -void ff_hevc_put_hevc_bi_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int16_t *src_16bit, \ - int height, \ - int denom, \ - int weight0, \ - int weight1, \ - int offset0, \ - int offset1, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ - \ - int shift = 14 + 1 - 8; \ - int log2Wd = denom + shift - 1; \ - \ - hevc_##DIR1##_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, \ - src_16bit, MAX_PB_SIZE, \ - dst, dst_stride, \ - filter, height, \ - weight0, weight1, offset0, \ - offset1, log2Wd); \ +#define BI_W_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ +void ff_hevc_put_hevc_bi_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t \ + dst_stride, \ + uint8_t *src, \ + ptrdiff_t \ + src_stride, \ + int16_t *src_16bit, \ + int height, \ + int denom, \ + int weight0, \ + int weight1, \ + int offset0, \ + int offset1, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ + int log2Wd = denom + 14 - 8; \ + \ + hevc_##DIR1##_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter, height, weight0, \ + weight1, offset0, offset1, \ + log2Wd); \ } BI_W_MC(qpel, h, 4, 8, hz, mx); @@ -5520,53 +5998,48 @@ BI_W_MC(epel, v, 32, 4, vt, my); #undef BI_W_MC -#define BI_W_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_bi_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int16_t *src_16bit, \ - int height, \ - int denom, \ - int weight0, \ - int weight1, \ - int offset0, \ - int offset1, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - int shift = 14 + 1 - 8; \ - int log2Wd = denom + shift - 1; \ - \ - hevc_##DIR1##_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, \ - src_16bit, MAX_PB_SIZE, \ - dst, dst_stride, \ - filter_x, filter_y, \ - height, weight0, weight1, \ - offset0, offset1, log2Wd); \ +#define BI_W_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_bi_w_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src_16bit, \ + int height, \ + int denom, \ + int weight0, \ + int weight1, \ + int offset0, \ + int offset1, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + int log2Wd = denom + 14 - 8; \ + \ + hevc_hv_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter_x, filter_y, height, \ + weight0, weight1, offset0, \ + offset1, log2Wd); \ } -BI_W_MC_HV(qpel, hv, 4, 8, hv); -BI_W_MC_HV(qpel, hv, 8, 8, hv); -BI_W_MC_HV(qpel, hv, 12, 8, hv); -BI_W_MC_HV(qpel, hv, 16, 8, hv); -BI_W_MC_HV(qpel, hv, 24, 8, hv); -BI_W_MC_HV(qpel, hv, 32, 8, hv); -BI_W_MC_HV(qpel, hv, 48, 8, hv); -BI_W_MC_HV(qpel, hv, 64, 8, hv); +BI_W_MC_HV(qpel, 4, 8); +BI_W_MC_HV(qpel, 8, 8); +BI_W_MC_HV(qpel, 12, 8); +BI_W_MC_HV(qpel, 16, 8); +BI_W_MC_HV(qpel, 24, 8); +BI_W_MC_HV(qpel, 32, 8); +BI_W_MC_HV(qpel, 48, 8); +BI_W_MC_HV(qpel, 64, 8); -BI_W_MC_HV(epel, hv, 4, 4, hv); -BI_W_MC_HV(epel, hv, 8, 4, hv); -BI_W_MC_HV(epel, hv, 6, 4, hv); -BI_W_MC_HV(epel, hv, 12, 4, hv); -BI_W_MC_HV(epel, hv, 16, 4, hv); -BI_W_MC_HV(epel, hv, 24, 4, hv); -BI_W_MC_HV(epel, hv, 32, 4, hv); +BI_W_MC_HV(epel, 4, 4); +BI_W_MC_HV(epel, 8, 4); +BI_W_MC_HV(epel, 6, 4); +BI_W_MC_HV(epel, 12, 4); +BI_W_MC_HV(epel, 16, 4); +BI_W_MC_HV(epel, 24, 4); +BI_W_MC_HV(epel, 32, 4); #undef BI_W_MC_HV diff --git a/libavcodec/mips/hevc_mc_uni_msa.c b/libavcodec/mips/hevc_mc_uni_msa.c index eead591ff..740c970ca 100644 --- a/libavcodec/mips/hevc_mc_uni_msa.c +++ b/libavcodec/mips/hevc_mc_uni_msa.c @@ -22,6 +22,85 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 3] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + /* 4 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20, + /* 4 width cases */ + 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 +}; + +#define HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, mask2, mask3, \ + filt0, filt1, filt2, filt3, \ + out0, out1) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ + \ + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ + DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ + DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4_m, vec5_m); \ + DPADD_SB2_SH(vec4_m, vec5_m, filt2, filt2, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec6_m, vec7_m); \ + DPADD_SB2_SH(vec6_m, vec7_m, filt3, filt3, out0, out1); \ +} + +#define HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, mask2, mask3, \ + filt0, filt1, filt2, filt3, \ + out0, out1, out2, out3) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ + \ + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2_m, vec3_m); \ + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt2, filt2, filt2, filt2, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4_m, vec5_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6_m, vec7_m); \ + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt1, filt1, filt1, filt1, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4_m, vec5_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6_m, vec7_m); \ + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt3, filt3, filt3, filt3, \ + out0, out1, out2, out3); \ +} + +#define HORIZ_4TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, filt0, filt1, \ + out0, out1) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ + \ + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ + DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ + DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, out0, out1); \ +} + +#define HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, filt0, filt1, \ + out0, out1, out2, out3) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ + \ + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); \ + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, \ + out0, out1, out2, out3); \ +} + static void copy_width8_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, int32_t height) @@ -204,114 +283,6 @@ static void copy_width64_msa(uint8_t *src, int32_t src_stride, } } -static const uint8_t mc_filt_mask_arr[16 * 3] = { - /* 8 width cases */ - 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - /* 4 width cases */ - 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20, - /* 4 width cases */ - 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 -}; - -#define FILT_8TAP_DPADD_S_H(vec0, vec1, vec2, vec3, \ - filt0, filt1, filt2, filt3) \ -( { \ - v8i16 tmp0, tmp1; \ - \ - tmp0 = __msa_dotp_s_h((v16i8) vec0, (v16i8) filt0); \ - tmp0 = __msa_dpadd_s_h(tmp0, (v16i8) vec1, (v16i8) filt1); \ - tmp1 = __msa_dotp_s_h((v16i8) vec2, (v16i8) filt2); \ - tmp1 = __msa_dpadd_s_h(tmp1, (v16i8) vec3, (v16i8) filt3); \ - tmp0 = __msa_adds_s_h(tmp0, tmp1); \ - \ - tmp0; \ -} ) - -#define HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, mask2, mask3, \ - filt0, filt1, filt2, filt3, \ - out0, out1) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ - v8i16 res0_m, res1_m, res2_m, res3_m; \ - \ - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ - DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, res0_m, res1_m); \ - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ - DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, res0_m, res1_m); \ - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4_m, vec5_m); \ - DOTP_SB2_SH(vec4_m, vec5_m, filt2, filt2, res2_m, res3_m); \ - VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec6_m, vec7_m); \ - DPADD_SB2_SH(vec6_m, vec7_m, filt3, filt3, res2_m, res3_m); \ - ADDS_SH2_SH(res0_m, res2_m, res1_m, res3_m, out0, out1); \ -} - -#define HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, mask2, mask3, \ - filt0, filt1, filt2, filt3, \ - out0, out1, out2, out3) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ - v8i16 res0_m, res1_m, res2_m, res3_m, res4_m, res5_m, res6_m, res7_m; \ - \ - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ - DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ - res0_m, res1_m, res2_m, res3_m); \ - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2_m, vec3_m); \ - DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt2, filt2, filt2, filt2, \ - res4_m, res5_m, res6_m, res7_m); \ - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4_m, vec5_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6_m, vec7_m); \ - DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt1, filt1, filt1, filt1, \ - res0_m, res1_m, res2_m, res3_m); \ - VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4_m, vec5_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6_m, vec7_m); \ - DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt3, filt3, filt3, filt3, \ - res4_m, res5_m, res6_m, res7_m); \ - ADDS_SH4_SH(res0_m, res4_m, res1_m, res5_m, res2_m, res6_m, res3_m, \ - res7_m, out0, out1, out2, out3); \ -} - -#define FILT_4TAP_DPADD_S_H(vec0, vec1, filt0, filt1) \ -( { \ - v8i16 tmp0; \ - \ - tmp0 = __msa_dotp_s_h((v16i8) vec0, (v16i8) filt0); \ - tmp0 = __msa_dpadd_s_h(tmp0, (v16i8) vec1, (v16i8) filt1); \ - \ - tmp0; \ -} ) - -#define HORIZ_4TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, filt0, filt1, \ - out0, out1) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ - \ - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ - DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, out0, out1); \ - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ - DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, out0, out1); \ -} - -#define HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, filt0, filt1, \ - out0, out1, out2, out3) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ - \ - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ - DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ - out0, out1, out2, out3); \ - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); \ - DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, \ - out0, out1, out2, out3); \ -} - static void common_hz_8t_4x4_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter) @@ -320,7 +291,7 @@ static void common_hz_8t_4x4_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v8i16 filt, out0, out1; - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); src -= 3; /* rearranging filter */ @@ -350,7 +321,7 @@ static void common_hz_8t_4x8_msa(uint8_t *src, int32_t src_stride, v16u8 mask0, mask1, mask2, mask3, out; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); src -= 3; /* rearranging filter */ @@ -387,7 +358,7 @@ static void common_hz_8t_4x16_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); src -= 3; /* rearranging filter */ @@ -450,47 +421,17 @@ static void common_hz_8t_4w_msa(uint8_t *src, int32_t src_stride, } } -static void common_hz_8t_8x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter) -{ - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; - v16u8 mask0, mask1, mask2, mask3, tmp0, tmp1; - v8i16 filt, out0, out1, out2, out3; - - mask0 = LD_UB(&mc_filt_mask_arr[0]); - src -= 3; - - /* rearranging filter */ - filt = LD_SH(filter); - SPLATI_H4_SB(filt, 0, 1, 2, 3, filt0, filt1, filt2, filt3); - - mask1 = mask0 + 2; - mask2 = mask0 + 4; - mask3 = mask0 + 6; - - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, - mask3, filt0, filt1, filt2, filt3, out0, out1, - out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - tmp0 = PCKEV_XORI128_UB(out0, out1); - tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); -} - -static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height) +static void common_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const int8_t *filter, int32_t height) { uint32_t loop_cnt; v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, tmp0, tmp1; + v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -505,9 +446,24 @@ static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride, LD_SB4(src, src_stride, src0, src1, src2, src3); XORI_B4_128_SB(src0, src1, src2, src3); src += (4 * src_stride); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, - mask3, filt0, filt1, filt2, filt3, out0, - out1, out2, out3); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt2, filt2, filt2, filt2, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4_m, vec5_m); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6_m, vec7_m); + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt1, filt1, filt1, filt1, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4_m, vec5_m); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6_m, vec7_m); + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt3, filt3, filt3, filt3, + out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); @@ -517,36 +473,22 @@ static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride, } } -static void common_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height) -{ - if (4 == height) { - common_hz_8t_8x4_msa(src, src_stride, dst, dst_stride, filter); - } else { - common_hz_8t_8x8mult_msa(src, src_stride, dst, dst_stride, filter, - height); - } -} - static void common_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - uint8_t *src1_ptr, *dst1; uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; - v8i16 filt, out0, out1, out2, out3; - v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask00, tmp0, tmp1; + v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask00; + v16u8 tmp0, tmp1, tmp2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 filt0, filt1, filt2, filt3; + v8i16 filt, out0, out1, out2, out3, out4, out5; - mask00 = LD_UB(&mc_filt_mask_arr[0]); - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask00 = LD_UB(&ff_hevc_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); - src1_ptr = src - 3; - dst1 = dst; - - dst = dst1 + 8; - src = src1_ptr + 8; + src = src - 3; /* rearranging filter */ filt = LD_SH(filter); @@ -559,32 +501,53 @@ static void common_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, mask5 = mask0 + 4; mask6 = mask0 + 6; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { /* 8 width */ - LD_SB4(src1_ptr, src_stride, src0, src1, src2, src3); + LD_SB4(src, src_stride, src0, src1, src2, src3); + /* 4 width */ + LD_SB4(src + 8, src_stride, src4, src5, src6, src7); + XORI_B4_128_SB(src0, src1, src2, src3); - src1_ptr += (4 * src_stride); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask00, mask1, mask2, - mask3, filt0, filt1, filt2, filt3, out0, - out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - tmp0 = PCKEV_XORI128_UB(out0, out1); - tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst1, dst_stride); - dst1 += (4 * dst_stride); + XORI_B4_128_SB(src4, src5, src6, src7); + src += (4 * src_stride); + + VSHF_B2_SB(src0, src0, src1, src1, mask00, mask00, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask00, mask00, vec2, vec3); + DOTP_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, out0, + out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, out0, + out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt1, filt1, filt1, filt1, out0, + out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt3, filt3, filt3, filt3, out0, + out1, out2, out3); /* 4 width */ - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask4, mask5, - mask6, filt0, filt1, filt2, filt3, out0, - out1); - SRARI_H2_SH(out0, out1, 6); - SAT_SH2_SH(out0, out1, 7); + VSHF_B2_SB(src4, src5, src6, src7, mask0, mask0, vec0, vec1); + DOTP_SB2_SH(vec0, vec1, filt0, filt0, out4, out5); + VSHF_B2_SB(src4, src5, src6, src7, mask4, mask4, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, filt1, filt1, out4, out5); + VSHF_B2_SB(src4, src5, src6, src7, mask5, mask5, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, out4, out5); + VSHF_B2_SB(src4, src5, src6, src7, mask6, mask6, vec6, vec7); + DPADD_SB2_SH(vec6, vec7, filt3, filt3, out4, out5); + + SRARI_H4_SH(out0, out1, out2, out3, 6); + SRARI_H2_SH(out4, out5, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + SAT_SH2_SH(out4, out5, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst, dst_stride); + tmp1 = PCKEV_XORI128_UB(out2, out3); + tmp2 = PCKEV_XORI128_UB(out4, out5); + + ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -594,11 +557,12 @@ static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 filt0, filt1, filt2, filt3; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -609,11 +573,17 @@ static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, mask2 = mask0 + 4; mask3 = mask0 + 6; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = (height >> 2); loop_cnt--;) { LD_SB2(src, src_stride, src0, src2); LD_SB2(src + 8, src_stride, src1, src3); - XORI_B4_128_SB(src0, src1, src2, src3); src += (2 * src_stride); + + LD_SB2(src, src_stride, src4, src6); + LD_SB2(src + 8, src_stride, src5, src7); + src += (2 * src_stride); + + XORI_B4_128_SB(src0, src1, src2, src3); + XORI_B4_128_SB(src4, src5, src6, src7); HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, mask3, filt0, filt1, filt2, filt3, out0, out1, out2, out3); @@ -625,6 +595,18 @@ static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, out = PCKEV_XORI128_UB(out2, out3); ST_UB(out, dst); dst += dst_stride; + + HORIZ_8TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, mask2, + mask3, filt0, filt1, filt2, filt3, out0, + out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + out = PCKEV_XORI128_UB(out0, out1); + ST_UB(out, dst); + dst += dst_stride; + out = PCKEV_XORI128_UB(out2, out3); + ST_UB(out, dst); + dst += dst_stride; } } @@ -637,10 +619,9 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7, out; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v16i8 vec11; - v8i16 out0, out1, out2, out3, out4, out5, out6, out7, out8, out9, out10; - v8i16 out11, filt; + v8i16 out0, out1, out2, out3, out8, out9, filt; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -655,7 +636,7 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = 16; loop_cnt--;) { LD_SB2(src, src_stride, src0, src2); LD_SB2(src + 16, src_stride, src1, src3); XORI_B4_128_SB(src0, src1, src2, src3); @@ -669,9 +650,9 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec8); VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec9); VSHF_B2_SB(src0, src1, src2, src3, mask6, mask6, vec1, vec3); - DOTP_SB4_SH(vec0, vec8, vec2, vec9, filt2, filt2, filt2, filt2, out4, - out10, out6, out11); - DOTP_SB2_SH(vec1, vec3, filt2, filt2, out5, out7); + DPADD_SB4_SH(vec0, vec8, vec2, vec9, filt2, filt2, filt2, filt2, + out0, out8, out2, out9); + DPADD_SB2_SH(vec1, vec3, filt2, filt2, out1, out3); VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec10); VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec11); VSHF_B2_SB(src0, src1, src2, src3, mask5, mask5, vec5, vec7); @@ -682,11 +663,8 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6, vec11); VSHF_B2_SB(src0, src1, src2, src3, mask7, mask7, vec5, vec7); DPADD_SB4_SH(vec4, vec10, vec6, vec11, filt3, filt3, filt3, filt3, - out4, out10, out6, out11); - DPADD_SB2_SH(vec5, vec7, filt3, filt3, out5, out7); - ADDS_SH4_SH(out0, out4, out8, out10, out2, out6, out9, out11, out0, - out8, out2, out9); - ADDS_SH2_SH(out1, out5, out3, out7, out1, out3); + out0, out8, out2, out9); + DPADD_SB2_SH(vec5, vec7, filt3, filt3, out1, out3); SRARI_H4_SH(out0, out8, out2, out9, 6); SRARI_H2_SH(out1, out3, 6); SAT_SH4_SH(out0, out8, out2, out9, 7); @@ -707,11 +685,12 @@ static void common_hz_8t_32w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 filt0, filt1, filt2, filt3; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -724,31 +703,32 @@ static void common_hz_8t_32w_msa(uint8_t *src, int32_t src_stride, for (loop_cnt = (height >> 1); loop_cnt--;) { src0 = LD_SB(src); + src1 = LD_SB(src + 8); src2 = LD_SB(src + 16); src3 = LD_SB(src + 24); - src1 = __msa_sldi_b(src2, src0, 8); src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); + + src4 = LD_SB(src); + src5 = LD_SB(src + 8); + src6 = LD_SB(src + 16); + src7 = LD_SB(src + 24); + src += src_stride; + XORI_B4_128_SB(src4, src5, src6, src7); + HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, mask3, filt0, filt1, filt2, filt3, out0, out1, out2, out3); SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); - src0 = LD_SB(src); - src2 = LD_SB(src + 16); - src3 = LD_SB(src + 24); - src1 = __msa_sldi_b(src2, src0, 8); - src += src_stride; - out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); out = PCKEV_XORI128_UB(out2, out3); ST_UB(out, dst + 16); dst += dst_stride; - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, + HORIZ_8TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, mask2, mask3, filt0, filt1, filt2, filt3, out0, out1, out2, out3); SRARI_H4_SH(out0, out1, out2, out3, 6); @@ -767,10 +747,11 @@ static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, { uint32_t loop_cnt; v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3, vec0, vec1, vec2; + v16i8 src4; v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7, out; - v8i16 filt, out0, out1, out2, out3, out4, out5, out6; + v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -785,11 +766,17 @@ static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB3(src, 16, src0, src2, src3); - src1 = __msa_sldi_b(src2, src0, 8); + for (loop_cnt = 64; loop_cnt--;) { + src0 = LD_SB(src); + src1 = LD_SB(src + 8); + src2 = LD_SB(src + 16); + src3 = LD_SB(src + 32); + src4 = LD_SB(src + 40); + src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); + src4 = (v16i8) __msa_xori_b((v16u8) src4, 128); + VSHF_B3_SB(src0, src0, src1, src1, src2, src2, mask0, mask0, mask0, vec0, vec1, vec2); DOTP_SB3_SH(vec0, vec1, vec2, filt0, filt0, filt0, out0, out1, out2); @@ -799,45 +786,42 @@ static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, out2 = __msa_dpadd_s_h(out2, vec2, filt1); VSHF_B3_SB(src0, src0, src1, src1, src2, src2, mask2, mask2, mask2, vec0, vec1, vec2); - DOTP_SB3_SH(vec0, vec1, vec2, filt2, filt2, filt2, out3, out4, out5); + DPADD_SB2_SH(vec0, vec1, filt2, filt2, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt2); + VSHF_B3_SB(src0, src0, src1, src1, src2, src2, mask3, mask3, mask3, vec0, vec1, vec2); - DPADD_SB2_SH(vec0, vec1, filt3, filt3, out3, out4); - out5 = __msa_dpadd_s_h(out5, vec2, filt3); - ADDS_SH2_SH(out0, out3, out1, out4, out0, out1); - out2 = __msa_adds_s_h(out2, out5); + DPADD_SB2_SH(vec0, vec1, filt3, filt3, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt3); + SRARI_H2_SH(out0, out1, 6); - out6 = __msa_srari_h(out2, 6); - SAT_SH3_SH(out0, out1, out6, 7); + out3 = __msa_srari_h(out2, 6); + SAT_SH3_SH(out0, out1, out3, 7); out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); - src1 = LD_SB(src + 40); - src += src_stride; - src1 = (v16i8) __msa_xori_b((v16u8) src1, 128); - - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask4, mask0, mask0, + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask4, mask0, mask0, vec0, vec1, vec2); DOTP_SB3_SH(vec0, vec1, vec2, filt0, filt0, filt0, out0, out1, out2); - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask5, mask1, mask1, + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask5, mask1, mask1, vec0, vec1, vec2); DPADD_SB2_SH(vec0, vec1, filt1, filt1, out0, out1); out2 = __msa_dpadd_s_h(out2, vec2, filt1); - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask6, mask2, mask2, + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask6, mask2, mask2, vec0, vec1, vec2); - DOTP_SB3_SH(vec0, vec1, vec2, filt2, filt2, filt2, out3, out4, out5); - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask7, mask3, mask3, + DPADD_SB2_SH(vec0, vec1, filt2, filt2, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt2); + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask7, mask3, mask3, vec0, vec1, vec2); - DPADD_SB2_SH(vec0, vec1, filt3, filt3, out3, out4); - out5 = __msa_dpadd_s_h(out5, vec2, filt3); - ADDS_SH2_SH(out0, out3, out1, out4, out3, out4); - out5 = __msa_adds_s_h(out2, out5); - SRARI_H2_SH(out3, out4, 6); - out5 = __msa_srari_h(out5, 6); - SAT_SH3_SH(out3, out4, out5, 7); - out = PCKEV_XORI128_UB(out6, out3); + DPADD_SB2_SH(vec0, vec1, filt3, filt3, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt3); + + SRARI_H2_SH(out0, out1, 6); + out2 = __msa_srari_h(out2, 6); + SAT_SH3_SH(out0, out1, out2, 7); + out = PCKEV_XORI128_UB(out3, out0); ST_UB(out, dst + 16); - out = PCKEV_XORI128_UB(out4, out5); + out = PCKEV_XORI128_UB(out1, out2); ST_UB(out, dst + 32); dst += dst_stride; } @@ -848,11 +832,13 @@ static void common_hz_8t_64w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, out; - v8i16 filt, out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 filt0, filt1, filt2, filt3; + v8i16 res0, res1, res2, res3, filt; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -864,37 +850,57 @@ static void common_hz_8t_64w_msa(uint8_t *src, int32_t src_stride, mask3 = mask0 + 6; for (loop_cnt = height; loop_cnt--;) { - src0 = LD_SB(src); - src2 = LD_SB(src + 16); - src3 = LD_SB(src + 24); - src1 = __msa_sldi_b(src2, src0, 8); - - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, - mask2, mask3, filt0, filt1, filt2, filt3, - out0, out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - out = PCKEV_XORI128_UB(out0, out1); - ST_UB(out, dst); - out = PCKEV_XORI128_UB(out2, out3); - ST_UB(out, dst + 16); - - src0 = LD_SB(src + 32); - src2 = LD_SB(src + 48); - src3 = LD_SB(src + 56); - src1 = __msa_sldi_b(src2, src0, 8); + LD_SB8(src, 8, src0, src1, src2, src3, src4, src5, src6, src7); src += src_stride; - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, - mask2, mask3, filt0, filt1, filt2, filt3, - out0, out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - out = PCKEV_XORI128_UB(out0, out1); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DOTP_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, res0, + res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, res0, + res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt1, filt1, filt1, filt1, res0, + res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt3, filt3, filt3, filt3, res0, + res1, res2, res3); + + SRARI_H4_SH(res0, res1, res2, res3, 6); + SAT_SH4_SH(res0, res1, res2, res3, 7); + out = PCKEV_XORI128_UB(res0, res1); + ST_UB(out, dst); + out = PCKEV_XORI128_UB(res2, res3); + ST_UB(out, dst + 16); + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + DOTP_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, res0, + res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, res0, + res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt1, filt1, filt1, filt1, res0, + res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask3, mask3, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask3, mask3, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt3, filt3, filt3, filt3, res0, + res1, res2, res3); + + SRARI_H4_SH(res0, res1, res2, res3, 6); + SAT_SH4_SH(res0, res1, res2, res3, 7); + out = PCKEV_XORI128_UB(res0, res1); ST_UB(out, dst + 32); - out = PCKEV_XORI128_UB(out2, out3); + out = PCKEV_XORI128_UB(res2, res3); ST_UB(out, dst + 48); dst += dst_stride; } @@ -905,12 +911,14 @@ static void common_vt_8t_4w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src13, src14; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r, src21_r, src43_r; v16i8 src65_r, src87_r, src109_r, src2110, src4332, src6554, src8776; + v16i8 src1110_r, src1211_r, src1312_r, src1413_r, src12111110, src14131312; v16i8 src10998, filt0, filt1, filt2, filt3; - v16u8 out; - v8i16 filt, out10, out32; + v8i16 filt, out10, out32, out54, out76; src -= (3 * src_stride); @@ -927,28 +935,45 @@ static void common_vt_8t_4w_msa(uint8_t *src, int32_t src_stride, src4332, src6554); XORI_B3_128_SB(src2110, src4332, src6554); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = (height >> 3); loop_cnt--;) { LD_SB4(src, src_stride, src7, src8, src9, src10); src += (4 * src_stride); + LD_SB4(src, src_stride, src11, src12, src13, src14); + src += (4 * src_stride); ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); + ILVR_B4_SB(src11, src10, src12, src11, src13, src12, src14, src13, + src1110_r, src1211_r, src1312_r, src1413_r); ILVR_D2_SB(src87_r, src76_r, src109_r, src98_r, src8776, src10998); + ILVR_D2_SB(src1211_r, src1110_r, src1413_r, src1312_r, + src12111110, src14131312); XORI_B2_128_SB(src8776, src10998); - out10 = FILT_8TAP_DPADD_S_H(src2110, src4332, src6554, src8776, filt0, - filt1, filt2, filt3); - out32 = FILT_8TAP_DPADD_S_H(src4332, src6554, src8776, src10998, filt0, - filt1, filt2, filt3); + XORI_B2_128_SB(src12111110, src14131312); + + DOTP_SB2_SH(src2110, src4332, filt0, filt0, out10, out32); + DOTP_SB2_SH(src6554, src8776, filt0, filt0, out54, out76); + DPADD_SB2_SH(src4332, src6554, filt1, filt1, out10, out32); + DPADD_SB2_SH(src8776, src10998, filt1, filt1, out54, out76); + DPADD_SB2_SH(src6554, src8776, filt2, filt2, out10, out32); + DPADD_SB2_SH(src10998, src12111110, filt2, filt2, out54, out76); + DPADD_SB2_SH(src8776, src10998, filt3, filt3, out10, out32); + DPADD_SB2_SH(src12111110, src14131312, filt3, filt3, out54, out76); SRARI_H2_SH(out10, out32, 6); + SRARI_H2_SH(out54, out76, 6); SAT_SH2_SH(out10, out32, 7); - out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + SAT_SH2_SH(out54, out76, 7); + out0 = PCKEV_XORI128_UB(out10, out32); + out1 = PCKEV_XORI128_UB(out54, out76); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); - src2110 = src6554; - src4332 = src8776; - src6554 = src10998; - src6 = src10; + src2110 = src10998; + src4332 = src12111110; + src6554 = src14131312; + src6 = src14; } } @@ -982,14 +1007,14 @@ static void common_vt_8t_8w_msa(uint8_t *src, int32_t src_stride, ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); - out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r, filt0, - filt1, filt2, filt3); - out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r, filt0, - filt1, filt2, filt3); - out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r, filt0, - filt1, filt2, filt3); - out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r, filt0, - filt1, filt2, filt3); + DOTP_SB4_SH(src10_r, src21_r, src32_r, src43_r, filt0, filt0, filt0, + filt0, out0_r, out1_r, out2_r, out3_r); + DPADD_SB4_SH(src32_r, src43_r, src54_r, src65_r, filt1, filt1, filt1, + filt1, out0_r, out1_r, out2_r, out3_r); + DPADD_SB4_SH(src54_r, src65_r, src76_r, src87_r, filt2, filt2, filt2, + filt2, out0_r, out1_r, out2_r, out3_r); + DPADD_SB4_SH(src76_r, src87_r, src98_r, src109_r, filt3, filt3, filt3, + filt3, out0_r, out1_r, out2_r, out3_r); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); @@ -1011,61 +1036,81 @@ static void common_vt_8t_12w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - int32_t loop_cnt; + uint32_t loop_cnt; uint32_t out2, out3; uint64_t out0, out1; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, res0, res1; - v16i8 res2, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - v8i16 vec01, vec23, vec45, vec67, tmp0, tmp1, tmp2; - v8i16 filt, filt0, filt1, filt2, filt3; - v4i32 mask = { 2, 6, 2, 6 }; + v16u8 tmp0, tmp1, tmp2, tmp3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 filt0, filt1, filt2, filt3; + v16i8 src10_r, src32_r, src54_r, src76_r, src98_r, src21_r, src43_r; + v16i8 src65_r, src87_r, src109_r, src10_l, src32_l, src54_l, src76_l; + v16i8 src98_l, src21_l, src43_l, src65_l, src87_l, src109_l; + v8i16 filt, out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; src -= (3 * src_stride); - /* rearranging filter_y */ filt = LD_SH(filter); - SPLATI_H4_SH(filt, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + SPLATI_H4_SB(filt, 0, 1, 2, 3, filt0, filt1, filt2, filt3); LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (7 * src_stride); XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - /* 4 width */ - VSHF_W2_SB(src0, src1, src1, src2, mask, mask, vec0, vec1); - VSHF_W2_SB(src2, src3, src3, src4, mask, mask, vec2, vec3); - VSHF_W2_SB(src4, src5, src5, src6, mask, mask, vec4, vec5); + ILVR_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, src10_r, src32_r, + src54_r, src21_r); + ILVR_B2_SB(src4, src3, src6, src5, src43_r, src65_r); + ILVL_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, src10_l, src32_l, + src54_l, src21_l); + ILVL_B2_SB(src4, src3, src6, src5, src43_l, src65_l); - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - src += (2 * src_stride); + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + XORI_B4_128_SB(src7, src8, src9, src10); + src += (4 * src_stride); - ILVR_B4_SH(src1, src0, src3, src2, src5, src4, src7, src6, - vec01, vec23, vec45, vec67); - tmp0 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1, - filt2, filt3); - ILVR_B4_SH(src2, src1, src4, src3, src6, src5, src8, src7, vec01, vec23, - vec45, vec67); - tmp1 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1, - filt2, filt3); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_l, + src87_l, src98_l, src109_l); + out0_r = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + out1_r = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + out2_r = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + out3_r = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + out0_l = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, filt0, + filt1, filt2, filt3); + out1_l = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, filt0, + filt1, filt2, filt3); + out2_l = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, filt0, + filt1, filt2, filt3); + out3_l = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, filt0, + filt1, filt2, filt3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, tmp0, tmp1, tmp2, tmp3); + XORI_B4_128_UB(tmp0, tmp1, tmp2, tmp3); - /* 4 width */ - VSHF_W2_SB(src6, src7, src7, src8, mask, mask, vec6, vec7); - ILVR_B4_SH(vec1, vec0, vec3, vec2, vec5, vec4, vec7, vec6, vec01, vec23, - vec45, vec67); - tmp2 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1, - filt2, filt3); - SRARI_H2_SH(tmp0, tmp1, 6); - tmp2 = __msa_srari_h(tmp2, 6); - SAT_SH3_SH(tmp0, tmp1, tmp2, 7); - PCKEV_B3_SB(tmp0, tmp0, tmp1, tmp1, tmp2, tmp2, res0, res1, res2); - XORI_B3_128_SB(res0, res1, res2); - - out0 = __msa_copy_u_d((v2i64) res0, 0); - out1 = __msa_copy_u_d((v2i64) res1, 0); - out2 = __msa_copy_u_w((v4i32) res2, 0); - out3 = __msa_copy_u_w((v4i32) res2, 1); + out0 = __msa_copy_u_d((v2i64) tmp0, 0); + out1 = __msa_copy_u_d((v2i64) tmp1, 0); + out2 = __msa_copy_u_w((v4i32) tmp0, 2); + out3 = __msa_copy_u_w((v4i32) tmp1, 2); + SD(out0, dst); + SW(out2, (dst + 8)); + dst += dst_stride; + SD(out1, dst); + SW(out3, (dst + 8)); + dst += dst_stride; + out0 = __msa_copy_u_d((v2i64) tmp2, 0); + out1 = __msa_copy_u_d((v2i64) tmp3, 0); + out2 = __msa_copy_u_w((v4i32) tmp2, 2); + out3 = __msa_copy_u_w((v4i32) tmp3, 2); SD(out0, dst); SW(out2, (dst + 8)); dst += dst_stride; @@ -1073,19 +1118,19 @@ static void common_vt_8t_12w_msa(uint8_t *src, int32_t src_stride, SW(out3, (dst + 8)); dst += dst_stride; - src0 = src2; - src1 = src3; - src2 = src4; - src3 = src5; - src4 = src6; - src5 = src7; - src6 = src8; - vec0 = vec2; - vec1 = vec3; - vec2 = vec4; - vec3 = vec5; - vec4 = vec6; - vec5 = vec7; + src10_r = src54_r; + src32_r = src76_r; + src54_r = src98_r; + src21_r = src65_r; + src43_r = src87_r; + src65_r = src109_r; + src10_l = src54_l; + src32_l = src76_l; + src54_l = src98_l; + src21_l = src65_l; + src43_l = src87_l; + src65_l = src109_l; + src6 = src10; } } @@ -1126,22 +1171,22 @@ static void common_vt_8t_16w_msa(uint8_t *src, int32_t src_stride, src87_r, src98_r, src109_r); ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_l, src87_l, src98_l, src109_l); - out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r, filt0, - filt1, filt2, filt3); - out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r, filt0, - filt1, filt2, filt3); - out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r, filt0, - filt1, filt2, filt3); - out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r, filt0, - filt1, filt2, filt3); - out0_l = FILT_8TAP_DPADD_S_H(src10_l, src32_l, src54_l, src76_l, filt0, - filt1, filt2, filt3); - out1_l = FILT_8TAP_DPADD_S_H(src21_l, src43_l, src65_l, src87_l, filt0, - filt1, filt2, filt3); - out2_l = FILT_8TAP_DPADD_S_H(src32_l, src54_l, src76_l, src98_l, filt0, - filt1, filt2, filt3); - out3_l = FILT_8TAP_DPADD_S_H(src43_l, src65_l, src87_l, src109_l, filt0, - filt1, filt2, filt3); + out0_r = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + out1_r = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + out2_r = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + out3_r = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + out0_l = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, filt0, + filt1, filt2, filt3); + out1_l = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, filt0, + filt1, filt2, filt3); + out2_l = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, filt0, + filt1, filt2, filt3); + out3_l = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, filt0, + filt1, filt2, filt3); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -1211,22 +1256,22 @@ static void common_vt_8t_16w_mult_msa(uint8_t *src, int32_t src_stride, src87_r, src98_r, src109_r); ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_l, src87_l, src98_l, src109_l); - out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3); - out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3); - out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3); - out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3); - out0_l = FILT_8TAP_DPADD_S_H(src10_l, src32_l, src54_l, src76_l, - filt0, filt1, filt2, filt3); - out1_l = FILT_8TAP_DPADD_S_H(src21_l, src43_l, src65_l, src87_l, - filt0, filt1, filt2, filt3); - out2_l = FILT_8TAP_DPADD_S_H(src32_l, src54_l, src76_l, src98_l, - filt0, filt1, filt2, filt3); - out3_l = FILT_8TAP_DPADD_S_H(src43_l, src65_l, src87_l, src109_l, - filt0, filt1, filt2, filt3); + out0_r = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, + filt0, filt1, filt2, filt3); + out1_r = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, + filt0, filt1, filt2, filt3); + out2_r = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, + filt0, filt1, filt2, filt3); + out3_r = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, + filt0, filt1, filt2, filt3); + out0_l = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, + filt0, filt1, filt2, filt3); + out1_l = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, + filt0, filt1, filt2, filt3); + out2_l = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, + filt0, filt1, filt2, filt3); + out3_l = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, + filt0, filt1, filt2, filt3); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -1301,37 +1346,34 @@ static void hevc_hv_uni_8t_4w_msa(uint8_t *src, int32_t height) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src9, src10, src11, src12, src13, src14; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8i16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 dst30, dst41, dst52, dst63, dst66, dst117, dst128, dst139, dst1410; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst1110_r, dst1312_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r, dst1211_r, dst1413_r; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; mask3 = mask0 + 6; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (7 * src_stride); XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); @@ -1343,61 +1385,91 @@ static void hevc_hv_uni_8t_4w_msa(uint8_t *src, VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - src += 2 * src_stride; - XORI_B2_128_SB(src7, src8); + for (loop_cnt = height >> 3; loop_cnt--;) { + LD_SB8(src, src_stride, src7, src8, src9, src10, src11, src12, src13, + src14); + src += (8 * src_stride); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src11, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); + VSHF_B4_SB(src8, src12, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + VSHF_B4_SB(src9, src13, mask0, mask1, mask2, mask3, + vec8, vec9, vec10, vec11); + VSHF_B4_SB(src10, src14, mask0, mask1, mask2, mask3, + vec12, vec13, vec14, vec15); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h(mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, + dst117 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst128 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst139 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, + filt2, filt3); + dst1410 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + + dst76_r = __msa_ilvr_h(dst117, dst66); + ILVRL_H2_SH(dst128, dst117, dst87_r, dst1211_r); + ILVRL_H2_SH(dst139, dst128, dst98_r, dst1312_r); + ILVRL_H2_SH(dst1410, dst139, dst109_r, dst1413_r); + dst117 = (v8i16) __msa_splati_d((v2i64) dst117, 1); + dst1110_r = __msa_ilvr_h(dst117, dst1410); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst4_r = HEVC_FILT_8TAP(dst54_r, dst76_r, dst98_r, dst1110_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst5_r = HEVC_FILT_8TAP(dst65_r, dst87_r, dst109_r, dst1211_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst6_r = HEVC_FILT_8TAP(dst76_r, dst98_r, dst1110_r, dst1312_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst7_r = HEVC_FILT_8TAP(dst87_r, dst109_r, dst1211_r, dst1413_r, filt_h0, filt_h1, filt_h2, filt_h3); - dst0_r >>= 6; - dst1_r >>= 6; - SRARI_W2_SW(dst0_r, dst1_r, 6); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRARI_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRARI_W4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SAT_SW4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 7); + SAT_SW4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 7); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst4_r, dst5_r); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst4_r, dst5_r); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10_r = dst98_r; + dst32_r = dst1110_r; + dst54_r = dst1312_r; + dst21_r = dst109_r; + dst43_r = dst1211_r; + dst65_r = dst1413_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst1410, 1); } } @@ -1412,11 +1484,12 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, uint32_t loop_cnt, cnt; uint8_t *src_tmp; uint8_t *dst_tmp; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; @@ -1425,20 +1498,17 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, v8i16 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; v8i16 dst21_l, dst43_l, dst65_l, dst87_l; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= ((3 * src_stride) + 3); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1461,18 +1531,14 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1480,33 +1546,29 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, vec4, vec5, vec6, vec7); VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); for (loop_cnt = height >> 1; loop_cnt--;) { LD_SB2(src_tmp, src_stride, src7, src8); XORI_B2_128_SB(src7, src8); src_tmp += 2 * src_stride; + ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, + dst10_r, dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, + dst10_l, dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); + ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, @@ -1518,9 +1580,8 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, @@ -1530,27 +1591,19 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, dst1_r >>= 6; dst1_l >>= 6; SRARI_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 6); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - dst1_r = CLIP_SW_0_255(dst1_r); - dst1_l = CLIP_SW_0_255(dst1_l); + SAT_SW4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 7); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; + dst0 = dst2; + dst1 = dst3; + dst2 = dst4; + dst3 = dst5; + dst4 = dst6; + dst5 = dst7; dst6 = dst8; } @@ -1579,11 +1632,232 @@ static void hevc_hv_uni_8t_12w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src13, src14; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 dst30, dst41, dst52, dst63, dst66, dst117, dst128, dst139, dst1410; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst76_l, dst21_l, dst43_l, dst65_l; + v8i16 dst87_r, dst98_r, dst1110_r, dst1312_r, dst109_r, dst1211_r; + v8i16 dst1413_r, dst87_l, filter_vec; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 dst0_l, dst1_l; - hevc_hv_uni_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + src -= ((3 * src_stride) + 3); + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB2(src_tmp, src_stride, src7, src8); + XORI_B2_128_SB(src7, src8); + src_tmp += 2 * src_stride; + + ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_r, + dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_l, + dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); + ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst1_l = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, + filt_h0, filt_h1, filt_h2, filt_h3); + dst1_r >>= 6; + dst1_l >>= 6; + SRARI_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SAT_SW4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 7); + + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0, dst1); + out0 = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out0, dst_tmp, dst_stride); + dst_tmp += (2 * dst_stride); + + dst0 = dst2; + dst1 = dst3; + dst2 = dst4; + dst3 = dst5; + dst4 = dst6; + dst5 = dst7; + dst6 = dst8; + } + + src += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src7, src8, src9, src10, src11, src12, src13, + src14); + src += (8 * src_stride); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); + + VSHF_B4_SB(src7, src11, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src12, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + VSHF_B4_SB(src9, src13, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src10, src14, mask4, mask5, mask6, mask7, vec12, vec13, + vec14, vec15); + + dst117 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst128 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst139 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, + filt2, filt3); + dst1410 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + + dst76_r = __msa_ilvr_h(dst117, dst66); + ILVRL_H2_SH(dst128, dst117, dst87_r, dst1211_r); + ILVRL_H2_SH(dst139, dst128, dst98_r, dst1312_r); + ILVRL_H2_SH(dst1410, dst139, dst109_r, dst1413_r); + dst117 = (v8i16) __msa_splati_d((v2i64) dst117, 1); + dst1110_r = __msa_ilvr_h(dst117, dst1410); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst4_r = HEVC_FILT_8TAP(dst54_r, dst76_r, dst98_r, dst1110_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst5_r = HEVC_FILT_8TAP(dst65_r, dst87_r, dst109_r, dst1211_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst6_r = HEVC_FILT_8TAP(dst76_r, dst98_r, dst1110_r, dst1312_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst7_r = HEVC_FILT_8TAP(dst87_r, dst109_r, dst1211_r, dst1413_r, + filt_h0, filt_h1, filt_h2, filt_h3); + + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRARI_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRARI_W4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SAT_SW4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 7); + SAT_SW4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 7); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst4_r, dst5_r); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst4_r, dst5_r); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10_r = dst98_r; + dst32_r = dst1110_r; + dst54_r = dst1312_r; + dst21_r = dst109_r; + dst43_r = dst1211_r; + dst65_r = dst1413_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst1410, 1); + } } static void hevc_hv_uni_8t_16w_msa(uint8_t *src, @@ -1654,7 +1928,7 @@ static void common_hz_4t_4x2_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, res0; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1666,7 +1940,7 @@ static void common_hz_4t_4x2_msa(uint8_t *src, int32_t src_stride, LD_SB2(src, src_stride, src0, src1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - res0 = FILT_4TAP_DPADD_S_H(vec0, vec1, filt0, filt1); + res0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); res0 = __msa_srari_h(res0, 6); res0 = __msa_sat_s_h(res0, 7); out = PCKEV_XORI128_UB(res0, res0); @@ -1681,7 +1955,7 @@ static void common_hz_4t_4x4_msa(uint8_t *src, int32_t src_stride, v8i16 filt, out0, out1; v16u8 out; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1708,7 +1982,7 @@ static void common_hz_4t_4x8_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1745,7 +2019,7 @@ static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1805,12 +2079,11 @@ static void common_hz_4t_6w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - uint32_t loop_cnt; v16i8 src0, src1, src2, src3, filt0, filt1, mask0, mask1; v16u8 out4, out5; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -1819,21 +2092,31 @@ static void common_hz_4t_6w_msa(uint8_t *src, int32_t src_stride, mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); + LD_SB4(src, src_stride, src0, src1, src2, src3); + src += (4 * src_stride); - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, - filt1, out0, out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); + XORI_B4_128_SB(src0, src1, src2, src3); + HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, + filt1, out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + out4 = PCKEV_XORI128_UB(out0, out1); + out5 = PCKEV_XORI128_UB(out2, out3); + ST6x4_UB(out4, out5, dst, dst_stride); + dst += (4 * dst_stride); - out4 = PCKEV_XORI128_UB(out0, out1); - out5 = PCKEV_XORI128_UB(out2, out3); - ST6x4_UB(out4, out5, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_SB4(src, src_stride, src0, src1, src2, src3); + src += (4 * src_stride); + + XORI_B4_128_SB(src0, src1, src2, src3); + HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, + filt1, out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + out4 = PCKEV_XORI128_UB(out0, out1); + out5 = PCKEV_XORI128_UB(out2, out3); + ST6x4_UB(out4, out5, dst, dst_stride); + dst += (4 * dst_stride); } static void common_hz_4t_8x2mult_msa(uint8_t *src, int32_t src_stride, @@ -1845,7 +2128,7 @@ static void common_hz_4t_8x2mult_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, vec0, vec1, vec2, vec3; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; filt = LD_SH(filter); @@ -1879,7 +2162,7 @@ static void common_hz_4t_8x4mult_msa(uint8_t *src, int32_t src_stride, v16u8 tmp0, tmp1; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -1928,8 +2211,8 @@ static void common_hz_4t_12w_msa(uint8_t *src, int32_t src_stride, v16u8 tmp0, tmp1; v8i16 filt, out0, out1, out2, out3, out4, out5; - mask0 = LD_SB(&mc_filt_mask_arr[0]); - mask2 = LD_SB(&mc_filt_mask_arr[32]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); + mask2 = LD_SB(&ff_hevc_mask_arr[32]); src -= 1; @@ -1940,32 +2223,33 @@ static void common_hz_4t_12w_msa(uint8_t *src, int32_t src_stride, mask1 = mask0 + 2; mask3 = mask2 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src0, src1, src2, src3); src += (4 * src_stride); XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec0, vec1); + DOTP_SB2_SH(vec0, vec1, filt0, filt0, out0, out1); + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, filt1, filt1, out0, out1); + SRARI_H2_SH(out0, out1, 6); + SAT_SH2_SH(out0, out1, 7); + tmp0 = PCKEV_XORI128_UB(out0, out1); + ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst + 8, dst_stride); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec4, vec5); VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec7); - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec0, vec1); DOTP_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt0, filt0, filt0, out2, out3, out4, out5); - DOTP_SB2_SH(vec0, vec1, filt0, filt0, out0, out1); VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec8, vec9); VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec10, vec11); - VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec2, vec3); DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt1, filt1, filt1, filt1, out2, out3, out4, out5); - DPADD_SB2_SH(vec2, vec3, filt1, filt1, out0, out1); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SRARI_H2_SH(out4, out5, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - SAT_SH2_SH(out4, out5, 7); + SRARI_H4_SH(out2, out3, out4, out5, 6); + SAT_SH4_SH(out2, out3, out4, out5, 7); tmp0 = PCKEV_XORI128_UB(out2, out3); tmp1 = PCKEV_XORI128_UB(out4, out5); ST8x4_UB(tmp0, tmp1, dst, dst_stride); - tmp0 = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -1977,10 +2261,11 @@ static void common_hz_4t_16w_msa(uint8_t *src, int32_t src_stride, uint32_t loop_cnt; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v16i8 filt0, filt1, mask0, mask1; + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; v8i16 filt, out0, out1, out2, out3, out4, out5, out6, out7; v16u8 out; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -1995,20 +2280,34 @@ static void common_hz_4t_16w_msa(uint8_t *src, int32_t src_stride, src += (4 * src_stride); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, - filt1, out0, out1, out2, out3); - HORIZ_4TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, filt0, - filt1, out4, out5, out6, out7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out0, out1, out2, out3); SRARI_H4_SH(out0, out1, out2, out3, 6); - SRARI_H4_SH(out4, out5, out6, out7, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); - SAT_SH4_SH(out4, out5, out6, out7, 7); out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); dst += dst_stride; out = PCKEV_XORI128_UB(out2, out3); ST_UB(out, dst); dst += dst_stride; + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out4, out5, out6, out7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out4, out5, out6, out7); + SRARI_H4_SH(out4, out5, out6, out7, 6); + SAT_SH4_SH(out4, out5, out6, out7, 7); out = PCKEV_XORI128_UB(out4, out5); ST_UB(out, dst); dst += dst_stride; @@ -2030,7 +2329,7 @@ static void common_hz_4t_24w_msa(uint8_t *src, int32_t src_stride, v8i16 filt, out0, out1, out2, out3; v16u8 tmp0, tmp1; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -2041,7 +2340,7 @@ static void common_hz_4t_24w_msa(uint8_t *src, int32_t src_stride, mask00 = mask0 + 8; mask11 = mask0 + 10; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 8; loop_cnt--;) { LD_SB4(src, src_stride, src0, src2, src4, src6); LD_SB4(src + 16, src_stride, src1, src3, src5, src7); src += (4 * src_stride); @@ -2109,9 +2408,10 @@ static void common_hz_4t_32w_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v16i8 filt0, filt1, mask0, mask1; v16u8 out; + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; v8i16 filt, out0, out1, out2, out3, out4, out5, out6, out7; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -2122,20 +2422,35 @@ static void common_hz_4t_32w_msa(uint8_t *src, int32_t src_stride, for (loop_cnt = (height >> 1); loop_cnt--;) { src0 = LD_SB(src); + src1 = LD_SB(src + 8); src2 = LD_SB(src + 16); src3 = LD_SB(src + 24); src += src_stride; src4 = LD_SB(src); + src5 = LD_SB(src + 8); src6 = LD_SB(src + 16); src7 = LD_SB(src + 24); - SLDI_B2_SB(src2, src6, src0, src4, src1, src5, 8); src += src_stride; XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, - filt0, filt1, out0, out1, out2, out3); - HORIZ_4TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, - filt0, filt1, out4, out5, out6, out7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out0, out1, out2, out3); + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out4, out5, out6, out7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out4, out5, out6, out7); SRARI_H4_SH(out0, out1, out2, out3, 6); SRARI_H4_SH(out4, out5, out6, out7, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); @@ -2177,7 +2492,7 @@ static void common_vt_4t_4x2_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - out10 = FILT_4TAP_DPADD_S_H(src2110, src4332, filt0, filt1); + out10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); out10 = __msa_srari_h(out10, 6); out10 = __msa_sat_s_h(out10, 7); out = PCKEV_XORI128_UB(out10, out10); @@ -2214,14 +2529,14 @@ static void common_vt_4t_4x4multiple_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - out10 = FILT_4TAP_DPADD_S_H(src2110, src4332, filt0, filt1); + out10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); src2 = LD_SB(src); src += (src_stride); ILVR_B2_SB(src5, src4, src2, src5, src54_r, src65_r); src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_r, (v2i64) src54_r); src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - out32 = FILT_4TAP_DPADD_S_H(src4332, src2110, filt0, filt1); + out32 = HEVC_FILT_4TAP_SH(src4332, src2110, filt0, filt1); SRARI_H2_SH(out10, out32, 6); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); @@ -2246,51 +2561,65 @@ static void common_vt_4t_6w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - uint32_t loop_cnt; - v16u8 src0, src1, src2, src3, vec0, vec1, vec2, vec3, out0, out1; - v8i16 vec01, vec12, vec23, vec30, tmp0, tmp1, tmp2, tmp3; - v8i16 filt, filt0, filt1; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r, filt0, filt1, filter_vec; src -= src_stride; - /* rearranging filter_y */ - filt = LD_SH(filter); - SPLATI_H2_SH(filt, 0, 1, filt0, filt1); + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_UB3(src, src_stride, src0, src1, src2); + LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - vec0 = (v16u8) __msa_xori_b((v16u8) src0, 128); - vec1 = (v16u8) __msa_xori_b((v16u8) src1, 128); - vec2 = (v16u8) __msa_xori_b((v16u8) src2, 128); + LD_SB2(src, src_stride, src3, src4); + src += (2 * src_stride); + XORI_B2_128_SB(src3, src4); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_UB4(src, src_stride, src3, src0, src1, src2); - src += (4 * src_stride); + dst0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); - vec3 = (v16u8) __msa_xori_b((v16u8) src3, 128); - ILVR_B2_SH(vec1, vec0, vec3, vec2, vec01, vec23); - tmp0 = FILT_4TAP_DPADD_S_H(vec01, vec23, filt0, filt1); + LD_SB2(src, src_stride, src5, src6); + src += (2 * src_stride); + XORI_B2_128_SB(src5, src6); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); - vec0 = __msa_xori_b((v16u8) src0, 128); - ILVR_B2_SH(vec2, vec1, vec0, vec3, vec12, vec30); - tmp1 = FILT_4TAP_DPADD_S_H(vec12, vec30, filt0, filt1); + dst2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); - vec1 = __msa_xori_b((v16u8) src1, 128); - vec01 = (v8i16) __msa_ilvr_b((v16i8) vec1, (v16i8) vec0); - tmp2 = FILT_4TAP_DPADD_S_H(vec23, vec01, filt0, filt1); + SRARI_H4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); + ST6x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); - vec2 = __msa_xori_b((v16u8) src2, 128); - vec12 = (v8i16) __msa_ilvr_b((v16i8) vec2, (v16i8) vec1); - tmp3 = FILT_4TAP_DPADD_S_H(vec30, vec12, filt0, filt1); + LD_SB2(src, src_stride, src3, src4); + src += (2 * src_stride); + XORI_B2_128_SB(src3, src4); + ILVR_B2_SB(src3, src6, src4, src3, src32_r, src43_r); - SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); - SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); - out0 = PCKEV_XORI128_UB(tmp0, tmp1); - out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST6x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - } + dst0_r = HEVC_FILT_4TAP_SH(src54_r, src32_r, filt0, filt1); + dst1_r = HEVC_FILT_4TAP_SH(src65_r, src43_r, filt0, filt1); + + LD_SB2(src, src_stride, src5, src6); + src += (2 * src_stride); + XORI_B2_128_SB(src5, src6); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + + dst2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + + SRARI_H4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); + ST6x4_UB(out0, out1, dst, dst_stride); } static void common_vt_4t_8x2_msa(uint8_t *src, int32_t src_stride, @@ -2310,9 +2639,9 @@ static void common_vt_4t_8x2_msa(uint8_t *src, int32_t src_stride, LD_SB5(src, src_stride, src0, src1, src2, src3, src4); XORI_B5_128_SB(src0, src1, src2, src3, src4); ILVR_B2_SH(src1, src0, src3, src2, src01, src23); - tmp0 = FILT_4TAP_DPADD_S_H(src01, src23, filt0, filt1); + tmp0 = HEVC_FILT_4TAP_SH(src01, src23, filt0, filt1); ILVR_B2_SH(src2, src1, src4, src3, src12, src34); - tmp1 = FILT_4TAP_DPADD_S_H(src12, src34, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src12, src34, filt0, filt1); SRARI_H2_SH(tmp0, tmp1, 6); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); @@ -2347,9 +2676,9 @@ static void common_vt_4t_8x6_msa(uint8_t *src, int32_t src_stride, XORI_B3_128_SB(src3, src4, src5); ILVR_B3_SH(src3, src2, src4, src3, src5, src4, vec1, vec3, vec4); - tmp0 = FILT_4TAP_DPADD_S_H(vec0, vec1, filt0, filt1); - tmp1 = FILT_4TAP_DPADD_S_H(vec2, vec3, filt0, filt1); - tmp2 = FILT_4TAP_DPADD_S_H(vec1, vec4, filt0, filt1); + tmp0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(vec1, vec4, filt0, filt1); SRARI_H2_SH(tmp0, tmp1, 6); tmp2 = __msa_srari_h(tmp2, 6); SAT_SH3_SH(tmp0, tmp1, tmp2, 7); @@ -2400,10 +2729,10 @@ static void common_vt_4t_8x4mult_msa(uint8_t *src, int32_t src_stride, XORI_B4_128_SB(src7, src8, src9, src10); ILVR_B4_SB(src7, src2, src8, src7, src9, src8, src10, src9, src72_r, src87_r, src98_r, src109_r); - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src72_r, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src87_r, filt0, filt1); - out2_r = FILT_4TAP_DPADD_S_H(src72_r, src98_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src87_r, src109_r, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src72_r, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src87_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src72_r, src98_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); @@ -2437,58 +2766,60 @@ static void common_vt_4t_12w_msa(uint8_t *src, int32_t src_stride, { uint32_t loop_cnt; v16i8 src0, src1, src2, src3, src4, src5, src6; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v16u8 out0, out1; - v8i16 src10, src21, src32, src43, src54, src65, src87, src109, src1211; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, filt, filt0, filt1; - v4u32 mask = { 2, 6, 2, 6 }; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; + v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; + v16i8 src2110, src4332, src6554; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, filt0, filt1; + v8i16 filter_vec; - /* rearranging filter_y */ - filt = LD_SH(filter); - SPLATI_H2_SH(filt, 0, 1, filt0, filt1); + src -= (1 * src_stride); - src -= src_stride; + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_W2_SB(src0, src1, src1, src2, mask, mask, vec0, vec1); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_l, (v2i64) src10_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src3, src4, src5, src6); src += (4 * src_stride); XORI_B4_128_SB(src3, src4, src5, src6); - ILVR_B2_SH(src1, src0, src3, src2, src10, src32); - VSHF_W2_SB(src2, src3, src3, src4, mask, mask, vec2, vec3); - VSHF_W2_SB(src4, src5, src5, src6, mask, mask, vec4, vec5); - tmp0 = FILT_4TAP_DPADD_S_H(src10, src32, filt0, filt1); - ILVR_B4_SH(src2, src1, src4, src3, src5, src4, src6, src5, - src21, src43, src54, src65); - tmp1 = FILT_4TAP_DPADD_S_H(src21, src43, filt0, filt1); - tmp2 = FILT_4TAP_DPADD_S_H(src32, src54, filt0, filt1); - tmp3 = FILT_4TAP_DPADD_S_H(src43, src65, filt0, filt1); - ILVR_B3_SH(vec1, vec0, vec3, vec2, vec5, vec4, src87, src109, src1211); - tmp4 = FILT_4TAP_DPADD_S_H(src87, src109, filt0, filt1); - tmp5 = FILT_4TAP_DPADD_S_H(src109, src1211, filt0, filt1); - SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); - SRARI_H2_SH(tmp4, tmp5, 6); - SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); - SAT_SH2_SH(tmp4, tmp5, 7); - out0 = PCKEV_XORI128_UB(tmp0, tmp1); - out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVL_B2_SB(src5, src4, src6, src5, src54_l, src65_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); + + dst0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst0_l = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst1_l = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + + SRARI_H4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRARI_H2_SH(dst0_l, dst1_l, 6); + SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); + SAT_SH2_SH(dst0_l, dst1_l, 7); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); ST8x4_UB(out0, out1, dst, dst_stride); - out0 = PCKEV_XORI128_UB(tmp4, tmp5); + out0 = PCKEV_XORI128_UB(dst0_l, dst1_l); ST4x4_UB(out0, out0, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); - src0 = src4; - src1 = src5; - src2 = src6; - vec0 = vec4; - vec1 = vec5; src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src2110 = src6554; } } @@ -2524,14 +2855,14 @@ static void common_vt_4t_16w_msa(uint8_t *src, int32_t src_stride, src32_r, src43_r, src54_r, src65_r); ILVL_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_l, src43_l, src54_l, src65_l); - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src32_r, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src43_r, filt0, filt1); - out2_r = FILT_4TAP_DPADD_S_H(src32_r, src54_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src43_r, src65_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src10_l, src32_l, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src21_l, src43_l, filt0, filt1); - out2_l = FILT_4TAP_DPADD_S_H(src32_l, src54_l, filt0, filt1); - out3_l = FILT_4TAP_DPADD_S_H(src43_l, src65_l, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + out2_l = HEVC_FILT_4TAP_SH(src32_l, src54_l, filt0, filt1); + out3_l = HEVC_FILT_4TAP_SH(src43_l, src65_l, filt0, filt1); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -2580,7 +2911,7 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, XORI_B3_128_SB(src6, src7, src8); ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 8; loop_cnt--;) { /* 16 width */ LD_SB2(src, src_stride, src3, src4); XORI_B2_128_SB(src3, src4); @@ -2594,14 +2925,14 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); /* 16 width */ - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src32_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src10_l, src32_l, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src43_r, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src21_l, src43_l, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); /* 8 width */ - out2_r = FILT_4TAP_DPADD_S_H(src76_r, src98_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src87_r, src109_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); /* 16 + 8 width */ SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); @@ -2634,14 +2965,14 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src11, src10, src8, src11, src76_r, src87_r); /* 16 width */ - out0_r = FILT_4TAP_DPADD_S_H(src32_r, src10_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src32_l, src10_l, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src43_r, src21_r, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src43_l, src21_l, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src32_l, src10_l, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src43_l, src21_l, filt0, filt1); /* 8 width */ - out2_r = FILT_4TAP_DPADD_S_H(src98_r, src76_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src109_r, src87_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src98_r, src76_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src109_r, src87_r, filt0, filt1); /* 16 + 8 width */ SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); @@ -2661,13 +2992,11 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, } } -static void common_vt_4t_32w_mult_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height, - int32_t width) +static void common_vt_4t_32w_msa(uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const int8_t *filter, int32_t height) { - uint32_t loop_cnt, cnt; - uint8_t *dst_tmp, *src_tmp; + uint32_t loop_cnt; v16i8 src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src76_r, src98_r; v16i8 src21_r, src43_r, src87_r, src109_r; @@ -2683,113 +3012,96 @@ static void common_vt_4t_32w_mult_msa(uint8_t *src, int32_t src_stride, filt = LD_SH(filter); SPLATI_H2_SB(filt, 0, 1, filt0, filt1); - for (cnt = (width >> 5); cnt--;) { - dst_tmp = dst; - src_tmp = src; + /* 16 width */ + LD_SB3(src, src_stride, src0, src1, src2); + XORI_B3_128_SB(src0, src1, src2); + + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + + /* next 16 width */ + LD_SB3(src + 16, src_stride, src6, src7, src8); + src += (3 * src_stride); + + XORI_B3_128_SB(src6, src7, src8); + ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); + ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); + + for (loop_cnt = (height >> 1); loop_cnt--;) { + /* 16 width */ + LD_SB2(src, src_stride, src3, src4); + XORI_B2_128_SB(src3, src4); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); /* 16 width */ - LD_SB3(src_tmp, src_stride, src0, src1, src2); - XORI_B3_128_SB(src0, src1, src2); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); - ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + /* 16 width */ + SRARI_H4_SH(out0_r, out1_r, out0_l, out1_l, 6); + SAT_SH4_SH(out0_r, out1_r, out0_l, out1_l, 7); + out = PCKEV_XORI128_UB(out0_r, out0_l); + ST_UB(out, dst); + out = PCKEV_XORI128_UB(out1_r, out1_l); + ST_UB(out, dst + dst_stride); + + src10_r = src32_r; + src21_r = src43_r; + src10_l = src32_l; + src21_l = src43_l; + src2 = src4; /* next 16 width */ - LD_SB3(src_tmp + 16, src_stride, src6, src7, src8); - src_tmp += (3 * src_stride); + LD_SB2(src + 16, src_stride, src9, src10); + src += (2 * src_stride); + XORI_B2_128_SB(src9, src10); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); - XORI_B3_128_SB(src6, src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); + /* next 16 width */ + out2_r = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + out2_l = HEVC_FILT_4TAP_SH(src76_l, src98_l, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + out3_l = HEVC_FILT_4TAP_SH(src87_l, src109_l, filt0, filt1); - for (loop_cnt = (height >> 1); loop_cnt--;) { - /* 16 width */ - LD_SB2(src_tmp, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + /* next 16 width */ + SRARI_H4_SH(out2_r, out3_r, out2_l, out3_l, 6); + SAT_SH4_SH(out2_r, out3_r, out2_l, out3_l, 7); + out = PCKEV_XORI128_UB(out2_r, out2_l); + ST_UB(out, dst + 16); + out = PCKEV_XORI128_UB(out3_r, out3_l); + ST_UB(out, dst + 16 + dst_stride); - /* 16 width */ - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src32_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src10_l, src32_l, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src43_r, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src21_l, src43_l, filt0, filt1); + dst += 2 * dst_stride; - /* 16 width */ - SRARI_H4_SH(out0_r, out1_r, out0_l, out1_l, 6); - SAT_SH4_SH(out0_r, out1_r, out0_l, out1_l, 7); - out = PCKEV_XORI128_UB(out0_r, out0_l); - ST_UB(out, dst_tmp); - out = PCKEV_XORI128_UB(out1_r, out1_l); - ST_UB(out, dst_tmp + dst_stride); - - src10_r = src32_r; - src21_r = src43_r; - src10_l = src32_l; - src21_l = src43_l; - src2 = src4; - - /* next 16 width */ - LD_SB2(src_tmp + 16, src_stride, src9, src10); - src_tmp += (2 * src_stride); - XORI_B2_128_SB(src9, src10); - ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); - ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); - - /* next 16 width */ - out2_r = FILT_4TAP_DPADD_S_H(src76_r, src98_r, filt0, filt1); - out2_l = FILT_4TAP_DPADD_S_H(src76_l, src98_l, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src87_r, src109_r, filt0, filt1); - out3_l = FILT_4TAP_DPADD_S_H(src87_l, src109_l, filt0, filt1); - - /* next 16 width */ - SRARI_H4_SH(out2_r, out3_r, out2_l, out3_l, 6); - SAT_SH4_SH(out2_r, out3_r, out2_l, out3_l, 7); - out = PCKEV_XORI128_UB(out2_r, out2_l); - ST_UB(out, dst_tmp + 16); - out = PCKEV_XORI128_UB(out3_r, out3_l); - ST_UB(out, dst_tmp + 16 + dst_stride); - - dst_tmp += 2 * dst_stride; - - src76_r = src98_r; - src87_r = src109_r; - src76_l = src98_l; - src87_l = src109_l; - src8 = src10; - } - - src += 32; - dst += 32; + src76_r = src98_r; + src87_r = src109_r; + src76_l = src98_l; + src87_l = src109_l; + src8 = src10; } } -static void common_vt_4t_32w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height) -{ - common_vt_4t_32w_mult_msa(src, src_stride, dst, dst_stride, - filter, height, 32); -} - static void hevc_hv_uni_4t_4x2_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, tmp; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43; + v4i32 dst0, dst1; src -= (src_stride + 1); @@ -2797,60 +3109,35 @@ static void hevc_hv_uni_4t_4x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); - XORI_B3_128_SB(src0, src1, src2); + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - dst0_r = (v4i32) __msa_srari_h((v8i16) dst0_r, 6); - dst0_r = (v4i32) CLIP_SH_0_255(dst0_r); - dst0_r = (v4i32) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); - - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp = __msa_srari_h(tmp, 6); + tmp = __msa_sat_s_h(tmp, 7); + out = PCKEV_XORI128_UB(tmp, tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, @@ -2858,20 +3145,19 @@ static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 out0_r, out1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filter_vec, tmp0, tmp1; + v8i16 dst30, dst41, dst52, dst63; + v8i16 dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 dst0, dst1, dst2, dst3; src -= (src_stride + 1); @@ -2879,78 +3165,38 @@ static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); - XORI_B3_128_SB(src0, src1, src2); + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - LD_SB4(src, src_stride, src3, src4, src5, src6); - XORI_B4_128_SB(src3, src4, src5, src6); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - - PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, out0_r, out1_r); - SRARI_H2_SH(out0_r, out1_r, 6); - CLIP_SH2_0_255(out0_r, out1_r); - out0_r = (v8i16) __msa_pckev_b((v16i8) out1_r, (v16i8) out0_r); - - ST4x4_UB(out0_r, out0_r, 0, 1, 2, 3, dst, dst_stride); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + SRARI_H2_SH(tmp0, tmp1, 6); + SAT_SH2_SH(tmp0, tmp1, 7); + out = PCKEV_XORI128_UB(tmp0, tmp1); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, @@ -2962,19 +3208,20 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, int32_t height) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5; v16i8 src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; + v8i16 filter_vec, tmp0, tmp1, tmp2, tmp3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v8i16 out0_r, out1_r, out2_r, out3_r; + v8i16 dst98_r, dst109_r; src -= (src_stride + 1); @@ -2982,33 +3229,23 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src, src_stride, @@ -3017,88 +3254,46 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); - dst32_r = __msa_ilvr_h(dst3, dst2); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst54_r = __msa_ilvr_h(dst5, dst4); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - dst65_r = __msa_ilvr_h(dst6, dst5); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - dst76_r = __msa_ilvr_h(dst7, dst6); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - dst87_r = __msa_ilvr_h(dst8, dst7); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - - /* row 9 */ - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - - /* row 10 */ - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); PCKEV_H4_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst5_r, dst4_r, dst7_r, dst6_r, - out0_r, out1_r, out2_r, out3_r); - - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - ST4x8_UB(out0_r, out1_r, dst, dst_stride); + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -3112,10 +3307,10 @@ static void hevc_hv_uni_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_hv_uni_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (4 == height) { hevc_hv_uni_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (0 == (height % 8)) { hevc_hv_uni_4t_4multx8mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height); @@ -3130,19 +3325,23 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - uint32_t loop_cnt; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6; + v16i8 src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filt_h0, filt_h1, filter_vec; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst4_r, dst5_r, dst6_r, dst7_r; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v8i16 out0_r, out1_r, out2_r, out3_r; + v8i16 dst54_r, dst76_r, dst98_r, dst65_r, dst87_r, dst109_r; + v8i16 dst98_l, dst65_l, dst54_l, dst76_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; src -= (src_stride + 1); @@ -3150,16 +3349,12 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); @@ -3169,79 +3364,78 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src, src_stride, src3, src4, src5, src6); - src += (4 * src_stride); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - XORI_B4_128_SB(src3, src4, src5, src6); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - out0_r, out1_r, out2_r, out3_r); - - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - ST6x4_UB(out0_r, out1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SRARI_H2_SH(tmp4, tmp5, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3,7); + SAT_SH2_SH(tmp4, tmp5,7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + out2 = PCKEV_XORI128_UB(tmp4, tmp5); + ST4x8_UB(out0, out1, dst, dst_stride); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, @@ -3249,16 +3443,15 @@ static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; @@ -3271,66 +3464,125 @@ static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, out0_r, out1_r); SRARI_H2_SH(out0_r, out1_r, 6); - CLIP_SH2_0_255(out0_r, out1_r); - out0_r = (v8i16) __msa_pckev_b((v16i8) out1_r, (v16i8) out0_r); + SAT_SH2_SH(out0_r, out1_r, 7); + out = PCKEV_XORI128_UB(out0_r, out1_r); + ST8x2_UB(out, dst, dst_stride); +} - ST8x2_UB(out0_r, dst, dst_stride); +static void hevc_hv_uni_4t_8multx4_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t width8mult) +{ + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + for (cnt = width8mult; cnt--;) { + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, @@ -3338,16 +3590,16 @@ static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v4i32 dst4_r, dst4_l, dst5_r, dst5_l; @@ -3363,157 +3615,104 @@ static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + src += (5 * src_stride); + LD_SB4(src, src_stride, src5, src6, src7, src8); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - - XORI_B2_128_SB(src5, src6); - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - - XORI_B2_128_SB(src7, src8); - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - - dst4_r >>= 6; - dst4_l >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, out0_r, out1_r, out2_r, out3_r); PCKEV_H2_SH(dst4_l, dst4_r, dst5_l, dst5_r, out4_r, out5_r); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H2_SH(out4_r, out5_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - CLIP_SH2_0_255(out4_r, out5_r); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH2_SH(out4_r, out5_r, 7); + out0 = PCKEV_XORI128_UB(out0_r, out1_r); + out1 = PCKEV_XORI128_UB(out2_r, out3_r); + out2 = PCKEV_XORI128_UB(out4_r, out5_r); - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - out2_r = (v8i16) __msa_pckev_b((v16i8) out5_r, (v16i8) out4_r); - - ST8x4_UB(out0_r, out1_r, dst, dst_stride); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(out2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } -static void hevc_hv_uni_4t_8w_mult_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - const int8_t *filter_x, - const int8_t *filter_y, - int32_t height, - int32_t width) +static void hevc_hv_uni_4t_8multx4mult_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t height, + int32_t width8mult) { uint32_t loop_cnt, cnt; uint8_t *src_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst54_r, dst54_l, dst65_r, dst65_l, dst6; v8i16 out0_r, out1_r, out2_r, out3_r; src -= (src_stride + 1); @@ -3522,17 +3721,13 @@ static void hevc_hv_uni_4t_8w_mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - for (cnt = width >> 3; cnt--;) { + for (cnt = width8mult; cnt--;) { src_tmp = src; dst_tmp = dst; @@ -3545,79 +3740,62 @@ static void hevc_hv_uni_4t_8w_mult_msa(uint8_t *src, VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - for (loop_cnt = height >> 2; loop_cnt--;) { + for (loop_cnt = (height >> 2); loop_cnt--;) { LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); src_tmp += (4 * src_stride); XORI_B4_128_SB(src3, src4, src5, src6); - /* row 3 */ VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - - dst3_r >>= 6; - dst3_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, out0_r, out1_r, out2_r, out3_r); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - ST8x4_UB(out0_r, out1_r, dst_tmp, dst_stride); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + out0 = PCKEV_XORI128_UB(out0_r, out1_r); + out1 = PCKEV_XORI128_UB(out2_r, out3_r); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src += 8; @@ -3635,13 +3813,16 @@ static void hevc_hv_uni_4t_8w_msa(uint8_t *src, { if (2 == height) { hevc_hv_uni_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); + } else if (4 == height) { + hevc_hv_uni_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_uni_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (0 == (height % 4)) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 1); } } @@ -3653,11 +3834,164 @@ static void hevc_hv_uni_4t_12w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - hevc_hv_uni_4t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + src_tmp = src; + dst_tmp = dst; + + LD_SB3(src_tmp, src_stride, src0, src1, src2); + src_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src += 8; + dst += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_uni_4t_16w_msa(uint8_t *src, @@ -3668,8 +4002,13 @@ static void hevc_hv_uni_4t_16w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 16); + if (4 == height) { + hevc_hv_uni_4t_8multx4_msa(src, src_stride, dst, dst_stride, filter_x, + filter_y, 2); + } else { + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 2); + } } static void hevc_hv_uni_4t_24w_msa(uint8_t *src, @@ -3680,8 +4019,8 @@ static void hevc_hv_uni_4t_24w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 24); + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 3); } static void hevc_hv_uni_4t_32w_msa(uint8_t *src, @@ -3692,8 +4031,8 @@ static void hevc_hv_uni_4t_32w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 32); + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 4); } #define UNI_MC_COPY(WIDTH) \ @@ -3721,15 +4060,13 @@ UNI_MC_COPY(64); #define UNI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ void ff_hevc_put_hevc_uni_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ { \ const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ \ @@ -3773,41 +4110,38 @@ UNI_MC(epel, v, 32, 4, vt, my); #undef UNI_MC -#define UNI_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_uni_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - hevc_##DIR1##_uni_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ - dst_stride, filter_x, \ - filter_y, height); \ +#define UNI_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_uni_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + \ + hevc_hv_uni_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, dst_stride, \ + filter_x, filter_y, height); \ } -UNI_MC_HV(qpel, hv, 4, 8, hv); -UNI_MC_HV(qpel, hv, 8, 8, hv); -UNI_MC_HV(qpel, hv, 12, 8, hv); -UNI_MC_HV(qpel, hv, 16, 8, hv); -UNI_MC_HV(qpel, hv, 24, 8, hv); -UNI_MC_HV(qpel, hv, 32, 8, hv); -UNI_MC_HV(qpel, hv, 48, 8, hv); -UNI_MC_HV(qpel, hv, 64, 8, hv); +UNI_MC_HV(qpel, 4, 8); +UNI_MC_HV(qpel, 8, 8); +UNI_MC_HV(qpel, 12, 8); +UNI_MC_HV(qpel, 16, 8); +UNI_MC_HV(qpel, 24, 8); +UNI_MC_HV(qpel, 32, 8); +UNI_MC_HV(qpel, 48, 8); +UNI_MC_HV(qpel, 64, 8); -UNI_MC_HV(epel, hv, 4, 4, hv); -UNI_MC_HV(epel, hv, 6, 4, hv); -UNI_MC_HV(epel, hv, 8, 4, hv); -UNI_MC_HV(epel, hv, 12, 4, hv); -UNI_MC_HV(epel, hv, 16, 4, hv); -UNI_MC_HV(epel, hv, 24, 4, hv); -UNI_MC_HV(epel, hv, 32, 4, hv); +UNI_MC_HV(epel, 4, 4); +UNI_MC_HV(epel, 6, 4); +UNI_MC_HV(epel, 8, 4); +UNI_MC_HV(epel, 12, 4); +UNI_MC_HV(epel, 16, 4); +UNI_MC_HV(epel, 24, 4); +UNI_MC_HV(epel, 32, 4); #undef UNI_MC_HV diff --git a/libavcodec/mips/hevc_mc_uniw_msa.c b/libavcodec/mips/hevc_mc_uniw_msa.c index 7c01c32d5..f9ecb414b 100644 --- a/libavcodec/mips/hevc_mc_uniw_msa.c +++ b/libavcodec/mips/hevc_mc_uniw_msa.c @@ -29,46 +29,6 @@ static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; -#define HEVC_HV_UNIW_RND_CLIP4(in0, in1, in2, in3, wgt, offset, rnd, \ - out0, out1, out2, out3) \ -{ \ - MUL4(in0, wgt, in1, wgt, in2, wgt, in3, wgt, out0, out1, out2, out3); \ - SRAR_W4_SW(out0, out1, out2, out3, rnd); \ - ADD4(out0, offset, out1, offset, out2, offset, out3, offset, \ - out0, out1, out2, out3); \ - out0 = CLIP_SW_0_255(out0); \ - out1 = CLIP_SW_0_255(out1); \ - out2 = CLIP_SW_0_255(out2); \ - out3 = CLIP_SW_0_255(out3); \ -} - -#define HEVC_UNIW_RND_CLIP2(in0, in1, wgt, offset, rnd, \ - out0_r, out1_r, out0_l, out1_l) \ -{ \ - ILVR_H2_SW(in0, in0, in1, in1, out0_r, out1_r); \ - ILVL_H2_SW(in0, in0, in1, in1, out0_l, out1_l); \ - DOTP_SH4_SW(out0_r, out1_r, out0_l, out1_l, wgt, wgt, wgt, wgt, \ - out0_r, out1_r, out0_l, out1_l); \ - SRAR_W4_SW(out0_r, out1_r, out0_l, out1_l, rnd); \ - ADD4(out0_r, offset, out1_r, offset, \ - out0_l, offset, out1_l, offset, \ - out0_r, out1_r, out0_l, out1_l); \ - out0_r = CLIP_SW_0_255(out0_r); \ - out1_r = CLIP_SW_0_255(out1_r); \ - out0_l = CLIP_SW_0_255(out0_l); \ - out1_l = CLIP_SW_0_255(out1_l); \ -} - -#define HEVC_UNIW_RND_CLIP4(in0, in1, in2, in3, wgt, offset, rnd, \ - out0_r, out1_r, out2_r, out3_r, \ - out0_l, out1_l, out2_l, out3_l) \ -{ \ - HEVC_UNIW_RND_CLIP2(in0, in1, wgt, offset, rnd, \ - out0_r, out1_r, out0_l, out1_l); \ - HEVC_UNIW_RND_CLIP2(in2, in3, wgt, offset, rnd, \ - out2_r, out3_r, out2_l, out3_l); \ -} - #define HEVC_UNIW_RND_CLIP2_MAX_SATU_H(in0_h, in1_h, wgt_w, offset_h, rnd_w, \ out0_h, out1_h) \ { \ @@ -1337,6 +1297,7 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src9, src10, src11, src12, src13, src14; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; @@ -1344,21 +1305,27 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, v16i8 src1110_r, src1211_r, src1312_r, src1413_r; v16i8 src2110, src4332, src6554, src8776, src10998; v16i8 src12111110, src14131312; - v8i16 dst10, dst32, dst54, dst76; + v8i16 filter_vec, dst01, dst23, dst45, dst67; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst0, dst1, dst2, dst3, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight = weight & 0x0000FFFF; + weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1387,28 +1354,21 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, src1413_r, src1312_r, src8776, src10998, src12111110, src14131312); XORI_B4_128_SB(src8776, src10998, src12111110, src14131312); + dst01 = HEVC_FILT_8TAP_SH(src2110, src4332, src6554, src8776, filt0, + filt1, filt2, filt3); + dst23 = HEVC_FILT_8TAP_SH(src4332, src6554, src8776, src10998, filt0, + filt1, filt2, filt3); + dst45 = HEVC_FILT_8TAP_SH(src6554, src8776, src10998, src12111110, + filt0, filt1, filt2, filt3); + dst67 = HEVC_FILT_8TAP_SH(src8776, src10998, src12111110, src14131312, + filt0, filt1, filt2, filt3); - dst10 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, filt0, filt1, - filt2, filt3, dst10, dst10, dst10, dst10); - dst32 = const_vec; - DPADD_SB4_SH(src4332, src6554, src8776, src10998, - filt0, filt1, filt2, filt3, dst32, dst32, dst32, dst32); - dst54 = const_vec; - DPADD_SB4_SH(src6554, src8776, src10998, src12111110, - filt0, filt1, filt2, filt3, dst54, dst54, dst54, dst54); - dst76 = const_vec; - DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, - filt0, filt1, filt2, filt3, dst76, dst76, dst76, dst76); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst01, dst23, dst45, dst67, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); - HEVC_UNIW_RND_CLIP4(dst10, dst32, dst54, dst76, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1429,24 +1389,30 @@ static void hevc_vt_uniwgt_8t_8w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec; + v8i16 dst0, dst1, dst2, dst3, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1464,28 +1430,21 @@ static void hevc_vt_uniwgt_8t_8w_msa(uint8_t *src, XORI_B4_128_SB(src7, src8, src9, src10); ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); + dst0 = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + dst1 = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + dst2 = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + dst3 = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1509,28 +1468,34 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v16i8 src10_l, src32_l, src54_l, src76_l, src98_l; v16i8 src21_l, src43_l, src65_l, src87_l, src109_l; v16i8 src2110, src4332, src6554, src8776, src10998; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 weight_vec_h, offset_vec, denom_vec, filter_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1547,7 +1512,7 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, ILVR_D3_SB(src21_l, src10_l, src43_l, src32_l, src65_l, src54_l, src2110, src4332, src6554); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src7, src8, src9, src10); src += (4 * src_stride); XORI_B4_128_SB(src7, src8, src9, src10); @@ -1558,37 +1523,28 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, src76_l, src87_l, src98_l, src109_l); ILVR_D2_SB(src87_l, src76_l, src109_l, src98_l, src8776, src10998); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); - tmp4 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, - filt0, filt1, filt2, filt3, tmp4, tmp4, tmp4, tmp4); - tmp5 = const_vec; - DPADD_SB4_SH(src4332, src6554, src8776, src10998, - filt0, filt1, filt2, filt3, tmp5, tmp5, tmp5, tmp5); + dst0 = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + dst1 = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + dst2 = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + dst3 = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + dst4 = HEVC_FILT_8TAP_SH(src2110, src4332, src6554, src8776, filt0, + filt1, filt2, filt3); + dst5 = HEVC_FILT_8TAP_SH(src4332, src6554, src8776, src10998, filt0, + filt1, filt2, filt3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp4, tmp5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); + ST4x4_UB(out2, out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1604,7 +1560,7 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, } } -static void hevc_vt_uniwgt_8t_16multx2mult_msa(uint8_t *src, +static void hevc_vt_uniwgt_8t_16multx4mult_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, @@ -1613,91 +1569,101 @@ static void hevc_vt_uniwgt_8t_16multx2mult_msa(uint8_t *src, int32_t weight, int32_t offset, int32_t rnd_val, - int32_t width) + int32_t weightmul16) { uint8_t *src_tmp; uint8_t *dst_tmp; int32_t loop_cnt, cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r; v16i8 src21_r, src43_r, src65_r, src87_r; - v8i16 tmp0, tmp1, tmp2, tmp3; v16i8 src10_l, src32_l, src54_l, src76_l; v16i8 src21_l, src43_l, src65_l, src87_l; + v16i8 src98_r, src109_r, src98_l, src109_l; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); - for (cnt = (width >> 4); cnt--;) { + for (cnt = weightmul16; cnt--;) { src_tmp = src; dst_tmp = dst; LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); src_tmp += (7 * src_stride); XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - ILVR_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, - src10_r, src32_r, src54_r, src21_r); - ILVR_B2_SB(src4, src3, src6, src5, src43_r, src65_r); - ILVL_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, - src10_l, src32_l, src54_l, src21_l); - ILVL_B2_SB(src4, src3, src6, src5, src43_l, src65_l); - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src_tmp, src_stride, src7, src8); - src_tmp += (2 * src_stride); - XORI_B2_128_SB(src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); + for (loop_cnt = (height >> 2); loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src7, src8, src9, src10); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src10_l, src32_l, src54_l, src76_l, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src21_l, src43_l, src65_l, src87_l, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); + ILVR_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, + src10_r, src32_r, src54_r, src21_r); + ILVR_B2_SB(src4, src3, src6, src5, src43_r, src65_r); + ILVL_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, + src10_l, src32_l, src54_l, src21_l); + ILVL_B2_SB(src4, src3, src6, src5, src43_l, src65_l); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, + src76_r, src87_r, src98_r, src109_r); + ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, + src76_l, src87_l, src98_l, src109_l); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0 = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + dst1 = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, filt0, + filt1, filt2, filt3); + dst2 = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + dst3 = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, filt0, + filt1, filt2, filt3); + dst4 = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + dst5 = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, filt0, + filt1, filt2, filt3); + dst6 = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + dst7 = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, filt0, + filt1, filt2, filt3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, + dst2, dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, + dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST_UB4(out0, out1, out2, out3, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); - src10_r = src32_r; - src32_r = src54_r; - src54_r = src76_r; - src21_r = src43_r; - src43_r = src65_r; - src65_r = src87_r; - src10_l = src32_l; - src32_l = src54_l; - src54_l = src76_l; - src21_l = src43_l; - src43_l = src65_l; - src65_l = src87_l; - src6 = src8; + src0 = src4; + src1 = src5; + src2 = src6; + src3 = src7; + src4 = src8; + src5 = src9; + src6 = src10; } src += 16; @@ -1715,9 +1681,9 @@ static void hevc_vt_uniwgt_8t_16w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, filter, height, weight, - offset, rnd_val, 16); + offset, rnd_val, 1); } static void hevc_vt_uniwgt_8t_24w_msa(uint8_t *src, @@ -1730,12 +1696,12 @@ static void hevc_vt_uniwgt_8t_24w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, - filter, height, weight, - offset, rnd_val, 16); + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, + filter, 32, weight, + offset, rnd_val, 1); hevc_vt_uniwgt_8t_8w_msa(src + 16, src_stride, dst + 16, dst_stride, - filter, height, weight, offset, rnd_val); + filter, 32, weight, offset, rnd_val); } static void hevc_vt_uniwgt_8t_32w_msa(uint8_t *src, @@ -1748,9 +1714,9 @@ static void hevc_vt_uniwgt_8t_32w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, filter, height, weight, - offset, rnd_val, 32); + offset, rnd_val, 2); } static void hevc_vt_uniwgt_8t_48w_msa(uint8_t *src, @@ -1763,9 +1729,9 @@ static void hevc_vt_uniwgt_8t_48w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, - filter, height, weight, - offset, rnd_val, 48); + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, + filter, 64, weight, + offset, rnd_val, 3); } static void hevc_vt_uniwgt_8t_64w_msa(uint8_t *src, @@ -1778,9 +1744,9 @@ static void hevc_vt_uniwgt_8t_64w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, filter, height, weight, - offset, rnd_val, 64); + offset, rnd_val, 4); } static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, @@ -1795,40 +1761,42 @@ static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r, weight_vec, offset_vec, rnd_vec; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r; + v4i32 weight_vec, offset_vec, rnd_vec, const_128, denom_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; mask3 = mask0 + 6; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + denom_vec = rnd_vec - 6; + + const_128 = __msa_ldi_w(128); + const_128 *= weight_vec; + offset_vec += __msa_srar_w(const_128, denom_vec); LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (7 * src_stride); @@ -1841,64 +1809,68 @@ static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src7, src8); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); - dst0_r >>= 6; - dst1_r >>= 6; + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); - SRAR_W2_SW(dst0_r, dst1_r, rnd_vec); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + SRAR_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, rnd_vec); ADD2(dst0_r, offset_vec, dst1_r, offset_vec, dst0_r, dst1_r); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); + ADD2(dst2_r, offset_vec, dst3_r, offset_vec, dst2_r, dst3_r); + CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst2_r, dst3_r); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + out = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } @@ -1921,7 +1893,7 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, v8i16 filt0, filt1, filt2, filt3; v4i32 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; @@ -1930,23 +1902,25 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, v8i16 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; v8i16 dst21_l, dst43_l, dst65_l, dst87_l; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v4i32 weight_vec, offset_vec, rnd_vec, const_128, denom_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= ((3 * src_stride) + 3); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + denom_vec = rnd_vec - 6; + + const_128 = __msa_ldi_w(128); + const_128 *= weight_vec; + offset_vec += __msa_srar_w(const_128, denom_vec); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; @@ -1969,18 +1943,14 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1988,15 +1958,12 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, vec4, vec5, vec6, vec7); VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_r, dst32_r, dst54_r, dst21_r); @@ -2012,9 +1979,8 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, @@ -2027,9 +1993,8 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, /* row 8 */ VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, @@ -2039,11 +2004,15 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, dst1_r >>= 6; dst1_l >>= 6; - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + MUL2(dst0_r, weight_vec, dst0_l, weight_vec, dst0_r, dst0_l); + MUL2(dst1_r, weight_vec, dst1_l, weight_vec, dst1_r, dst1_l); + SRAR_W4_SW(dst0_r, dst1_r, dst0_l, dst1_l, rnd_vec); + ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); + ADD2(dst1_r, offset_vec, dst1_l, offset_vec, dst1_r, dst1_l); + CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); + PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); + dst0_r = (v4i32) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); ST8x2_UB(dst0_r, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); @@ -2094,12 +2063,198 @@ static void hevc_hv_uniwgt_8t_12w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_hv_uniwgt_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val, 8); - hevc_hv_uniwgt_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height, weight, offset, - rnd_val); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst10_l, dst32_l, dst54_l; + v8i16 dst98_r, dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v8i16 dst76_l, filter_vec; + v4i32 dst0_r, dst0_l, dst1_r, dst2_r, dst3_r; + v4i32 weight_vec, offset_vec, rnd_vec, const_128, denom_vec; + + src -= ((3 * src_stride) + 3); + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + weight_vec = __msa_fill_w(weight); + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val); + denom_vec = rnd_vec - 6; + + const_128 = __msa_ldi_w(128); + const_128 *= weight_vec; + offset_vec += __msa_srar_w(const_128, denom_vec); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 16; loop_cnt--;) { + src7 = LD_SB(src_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src_tmp += src_stride; + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + MUL2(dst0_r, weight_vec, dst0_l, weight_vec, dst0_r, dst0_l); + SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); + ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); + CLIP_SW2_0_255_MAX_SATU(dst0_r, dst0_l); + dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + out = (v16u8) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); + ST8x1_UB(out, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; + } + + src += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + SRAR_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, rnd_vec); + ADD2(dst0_r, offset_vec, dst1_r, offset_vec, dst0_r, dst1_r); + ADD2(dst2_r, offset_vec, dst3_r, offset_vec, dst2_r, dst3_r); + CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst2_r, dst3_r); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + out = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_uniwgt_8t_16w_msa(uint8_t *src, @@ -2187,19 +2342,19 @@ static void hevc_hz_uniwgt_4t_4x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v8i16 filt0, filt1; v16i8 src0, src1, vec0, vec1; v16i8 mask1; v8i16 dst0; v4i32 dst0_r, dst0_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; @@ -2210,29 +2365,33 @@ static void hevc_hz_uniwgt_4t_4x2_msa(uint8_t *src, weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + LD_SB2(src, src_stride, src0, src1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); ILVRL_H2_SW(dst0, dst0, dst0_r, dst0_l); DOTP_SH2_SW(dst0_r, dst0_l, weight_vec, weight_vec, dst0_r, dst0_l); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + dst0 = __msa_adds_s_h(dst0, offset_vec); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); + out = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); + ST4x2_UB(out, dst, dst_stride); dst += (4 * dst_stride); } @@ -2241,19 +2400,18 @@ static void hevc_hz_uniwgt_4t_4x4_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask1, vec0, vec1; + v16i8 mask1, vec0, vec1, vec2, vec3; v8i16 dst0, dst1; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; @@ -2265,29 +2423,32 @@ static void hevc_hz_uniwgt_4t_4x4_msa(uint8_t *src, weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + LD_SB4(src, src_stride, src0, src1, src2, src3); XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec2, vec3); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); - HEVC_UNIW_RND_CLIP2(dst0, dst1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -2302,14 +2463,15 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v16i8 mask1, vec0, vec1; + v16i8 mask1, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v8i16 filter_vec; + v8i16 weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; @@ -2317,13 +2479,20 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; for (loop_cnt = (height >> 3); loop_cnt--;) { @@ -2333,29 +2502,20 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2372,10 +2532,10 @@ static void hevc_hz_uniwgt_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_hz_uniwgt_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (4 == height) { hevc_hz_uniwgt_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (8 == height || 16 == height) { hevc_hz_uniwgt_4t_4x8multiple_msa(src, src_stride, dst, dst_stride, filter, height, weight, @@ -2393,16 +2553,15 @@ static void hevc_hz_uniwgt_4t_6w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; v8i16 filt0, filt1; - v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v16i8 vec0, vec1; - v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2410,48 +2569,53 @@ static void hevc_hz_uniwgt_4t_6w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); + LD_SB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - XORI_B4_128_SB(src0, src1, src2, src3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST6x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST6x4_UB(out2, out3, dst, dst_stride); } static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, @@ -2459,19 +2623,18 @@ static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v8i16 filt0, filt1, dst0, dst1; v16i8 src0, src1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2479,52 +2642,113 @@ static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; LD_SB2(src, src_stride, src0, src1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); - HEVC_UNIW_RND_CLIP2(dst0, dst1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out, dst, dst_stride); } -static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, +static void hevc_hz_uniwgt_4t_8x4_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out0, out1; + v16i8 src0, src1, src2, src3; + v16i8 mask0, mask1, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, dst0, dst1, dst2, dst3; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + + src -= 1; + + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + weight = weight & 0x0000FFFF; + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + mask0 = LD_SB(&ff_hevc_mask_arr[0]); + mask1 = mask0 + 2; + + LD_SB4(src, src_stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); +} + +static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t weight, + int32_t offset, + int32_t rnd_val) +{ + v16u8 out0, out1, out2; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2532,61 +2756,52 @@ static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; - LD_SB6(src, src_stride, src0, src1, src2, src3, src4, src5); LD_SB6(src, src_stride, src0, src1, src2, src3, src4, src5); XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, + dst4, dst5); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_UNIW_RND_CLIP2(dst4, dst5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } -static void hevc_hz_uniwgt_4t_8x4multiple_msa(uint8_t *src, +static void hevc_hz_uniwgt_4t_8x8multiple_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, @@ -2598,14 +2813,14 @@ static void hevc_hz_uniwgt_4t_8x4multiple_msa(uint8_t *src, { uint32_t loop_cnt; v8i16 filt0, filt1; - v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; - v8i16 dst0, dst1, dst2, dst3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2613,47 +2828,56 @@ static void hevc_hz_uniwgt_4t_8x4multiple_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - XORI_B4_128_SB(src0, src1, src2, src3); + for (loop_cnt = (height >> 3); loop_cnt--;) { + LD_SB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); + src += (8 * src_stride); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + dst += (8 * dst_stride); } } @@ -2669,12 +2893,15 @@ static void hevc_hz_uniwgt_4t_8w_msa(uint8_t *src, { if (2 == height) { hevc_hz_uniwgt_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); + } else if (4 == height) { + hevc_hz_uniwgt_4t_8x4_msa(src, src_stride, dst, dst_stride, + filter, weight, offset, rnd_val); } else if (6 == height) { hevc_hz_uniwgt_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else { - hevc_hz_uniwgt_4t_8x4multiple_msa(src, src_stride, dst, dst_stride, + hevc_hz_uniwgt_4t_8x8multiple_msa(src, src_stride, dst, dst_stride, filter, height, weight, offset, rnd_val); } @@ -2691,19 +2918,18 @@ static void hevc_hz_uniwgt_4t_12w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1, out2; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v16i8 mask3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v16i8 mask3, vec11; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2711,60 +2937,51 @@ static void hevc_hz_uniwgt_4t_12w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; mask3 = mask2 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src0, src1, src2, src3); src += (4 * src_stride); XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec8, vec9); + VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec10, vec11); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_UNIW_RND_CLIP2(dst4, dst5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2780,15 +2997,15 @@ static void hevc_hz_uniwgt_4t_16w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2796,13 +3013,20 @@ static void hevc_hz_uniwgt_4t_16w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; for (loop_cnt = (height >> 2); loop_cnt--;) { @@ -2813,56 +3037,35 @@ static void hevc_hz_uniwgt_4t_16w_msa(uint8_t *src, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + PCKEV_B4_UB(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + out0, out1, out2, out3); - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - HEVC_UNIW_RND_CLIP4(dst4, dst5, dst6, dst7, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); } } @@ -2877,16 +3080,14 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; - uint8_t *dst_tmp = dst + 16; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3; v8i16 filt0, filt1; - v8i16 dst0, dst1, dst2, dst3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; - v16i8 mask1, mask2, mask3; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 mask0, mask1, mask2, mask3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2894,19 +3095,25 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + mask0 = LD_SB(&ff_hevc_mask_arr[0]); mask1 = mask0 + 2; mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { - /* 16 width */ + for (loop_cnt = 16; loop_cnt--;) { LD_SB2(src, src_stride, src0, src2); LD_SB2(src + 16, src_stride, src1, src3); src += (2 * src_stride); @@ -2914,46 +3121,29 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - /* 8 width */ + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec2, vec3); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - HEVC_UNIW_RND_CLIP2(dst0, dst1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST_UB2(out0, out1, dst, dst_stride); + ST8x2_UB(out2, dst + 16, dst_stride); + dst += (2 * dst_stride); } } @@ -2968,15 +3158,15 @@ static void hevc_hz_uniwgt_4t_32w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; - v16i8 src0, src1, src2; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; - v8i16 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2984,13 +3174,20 @@ static void hevc_hz_uniwgt_4t_32w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; mask2 = mask0 + 8; mask3 = mask0 + 10; @@ -2999,65 +3196,40 @@ static void hevc_hz_uniwgt_4t_32w_msa(uint8_t *src, LD_SB2(src, 16, src0, src1); src2 = LD_SB(src + 24); src += src_stride; - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); - dst += dst_stride; - - LD_SB2(src, 16, src0, src1); - src2 = LD_SB(src + 24); + LD_SB2(src, 16, src3, src4); + src5 = LD_SB(src + 24); src += src_stride; - - XORI_B3_128_SB(src0, src1, src2); - + XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src3, src4, src3, src4, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST_UB2(out0, out1, dst, 16); + dst += dst_stride; + ST_UB2(out2, out3, dst, 16); dst += dst_stride; } } @@ -3067,55 +3239,54 @@ static void hevc_vt_uniwgt_4t_4x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v16i8 src10_r, src32_r, src21_r, src43_r; v16i8 src2110, src4332; - v8i16 dst10; + v8i16 dst0; v4i32 dst0_r, dst0_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - LD_SB2(src, src_stride, src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); - src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - - ILVRL_H2_SW(dst10, dst10, dst0_r, dst0_l); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + dst0 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + ILVRL_H2_SW(dst0, dst0, dst0_r, dst0_l); DOTP_SH2_SW(dst0_r, dst0_l, weight_vec, weight_vec, dst0_r, dst0_l); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + dst0 = __msa_adds_s_h(dst0, offset_vec); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); + out = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); + ST4x2_UB(out, dst, dst_stride); } static void hevc_vt_uniwgt_4t_4x4_msa(uint8_t *src, @@ -3123,55 +3294,53 @@ static void hevc_vt_uniwgt_4t_4x4_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v16i8 src10_r, src32_r, src54_r, src21_r, src43_r, src65_r; v16i8 src2110, src4332, src6554; - v8i16 dst10, dst32; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; + v8i16 dst0, dst1; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - - LD_SB4(src, src_stride, src3, src4, src5, src6); ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, src54_r, src65_r); - ILVR_D2_SB(src43_r, src32_r, src65_r, src54_r, src4332, src6554); - XORI_B2_128_SB(src4332, src6554); + ILVR_D3_SB(src21_r, src10_r, src43_r, src32_r, src65_r, src54_r, + src2110, src4332, src6554); + XORI_B3_128_SB(src2110, src4332, src6554); + dst0 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - HEVC_UNIW_RND_CLIP2(dst10, dst32, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, @@ -3185,26 +3354,33 @@ static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; v16i8 src2110, src4332, src6554, src8776; - v8i16 dst10, dst32, dst54, dst76; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 src10998; + v8i16 dst0, dst1, dst2, dst3, filt0, filt1; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3215,39 +3391,31 @@ static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); - src += (6 * src_stride); + LD_SB8(src, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, src54_r, src65_r); ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVR_D3_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, - src4332, src6554, src8776); - XORI_B3_128_SB(src4332, src6554, src8776); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, + src109_r, src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + dst0 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src6554, src8776, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src8776, src10998, filt0, filt1); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - dst54 = const_vec; - DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - LD_SB2(src, src_stride, src9, src2); - src += (2 * src_stride); - ILVR_B2_SB(src9, src8, src2, src9, src98_r, src109_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src109_r, (v2i64) src98_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - - dst76 = const_vec; - DPADD_SB2_SH(src8776, src2110, filt0, filt1, dst76, dst76); - HEVC_UNIW_RND_CLIP4(dst10, dst32, dst54, dst76, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + src2 = src10; + src2110 = src10998; } } @@ -3263,10 +3431,10 @@ static void hevc_vt_uniwgt_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_vt_uniwgt_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (4 == height) { hevc_vt_uniwgt_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (0 == (height % 8)) { hevc_vt_uniwgt_4t_4x8multiple_msa(src, src_stride, dst, dst_stride, filter, height, weight, offset, @@ -3284,64 +3452,66 @@ static void hevc_vt_uniwgt_4t_6w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1, tmp2, tmp3; + v16i8 src54_r, src65_r, src76_r, src87_r, src98_r, src109_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); XORI_B3_128_SB(src0, src1, src2); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - - LD_SB2(src, src_stride, src1, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src1, src2); - ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST6x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST6x4_UB(out2, out3, dst, dst_stride); } static void hevc_vt_uniwgt_4t_8x2_msa(uint8_t *src, @@ -3349,49 +3519,105 @@ static void hevc_vt_uniwgt_4t_8x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1; + v8i16 dst0, dst1; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - HEVC_UNIW_RND_CLIP2(tmp0, tmp1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out, dst, dst_stride); +} + +static void hevc_vt_uniwgt_4t_8x4_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t weight, + int32_t offset, + int32_t rnd_val) +{ + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4; + v16i8 src10_r, src32_r, src21_r, src43_r; + v16i8 src5, src6, src54_r, src65_r; + v8i16 filt0, filt1; + v8i16 dst0, dst1, dst2, dst3; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + + src -= src_stride; + + weight = weight & 0x0000FFFF; + + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (3 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); } static void hevc_vt_uniwgt_4t_8x6_msa(uint8_t *src, @@ -3399,101 +3625,102 @@ static void hevc_vt_uniwgt_4t_8x6_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r; v16i8 src21_r, src43_r, src65_r, src87_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); + + XORI_B3_128_SB(src0, src1, src2); XORI_B6_128_SB(src3, src4, src5, src6, src7, src8); - ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, - src32_r, src43_r, src54_r, src65_r); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, tmp3, tmp3); - tmp4 = const_vec; - DPADD_SB2_SH(src54_r, src76_r, filt0, filt1, tmp4, tmp4); - tmp5 = const_vec; - DPADD_SB2_SH(src65_r, src87_r, filt0, filt1, tmp5, tmp5); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp4, tmp5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, dst3); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, + dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } -static void hevc_vt_uniwgt_4t_8x4multiple_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - const int8_t *filter, - int32_t height, - int32_t weight, - int32_t offset, - int32_t rnd_val) +static void hevc_vt_uniwgt_4t_8x8mult_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t height, + int32_t weight, + int32_t offset, + int32_t rnd_val) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1, tmp2, tmp3; + v16i8 src54_r, src65_r, src76_r, src87_r, src98_r, src109_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3502,35 +3729,37 @@ static void hevc_vt_uniwgt_4t_8x4multiple_msa(uint8_t *src, XORI_B3_128_SB(src0, src1, src2); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); + for (loop_cnt = (height >> 3); loop_cnt--;) { + LD_SB8(src, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + dst += (8 * dst_stride); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - - LD_SB2(src, src_stride, src1, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src1, src2); - ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); + src2 = src10; + src10_r = src98_r; + src21_r = src109_r; } } @@ -3546,14 +3775,17 @@ static void hevc_vt_uniwgt_4t_8w_msa(uint8_t *src, { if (2 == height) { hevc_vt_uniwgt_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); + } else if (4 == height) { + hevc_vt_uniwgt_4t_8x4_msa(src, src_stride, dst, dst_stride, + filter, weight, offset, rnd_val); } else if (6 == height) { hevc_vt_uniwgt_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else { - hevc_vt_uniwgt_4t_8x4multiple_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, - rnd_val); + hevc_vt_uniwgt_4t_8x8mult_msa(src, src_stride, dst, dst_stride, + filter, height, weight, offset, + rnd_val); } } @@ -3568,27 +3800,35 @@ static void hevc_vt_uniwgt_4t_12w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; v16i8 src2110, src4332; + v16i8 src54_r, src76_r, src98_r, src65_r, src87_r, src109_r; + v16i8 src76_l, src98_l, src87_l, src109_l, src6554, src8776, src10998; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 dst9, dst10, dst11, filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (1 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3599,47 +3839,56 @@ static void hevc_vt_uniwgt_4t_12w_msa(uint8_t *src, ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_l, (v2i64) src10_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + ILVRL_B2_SB(src3, src2, src32_r, src32_l); + ILVRL_B2_SB(src4, src3, src43_r, src43_l); + ILVRL_B2_SB(src5, src4, src54_r, src54_l); + ILVRL_B2_SB(src6, src5, src65_r, src65_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); - - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp4 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, tmp4, tmp4); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - tmp5 = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, tmp5, tmp5); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp4, tmp5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); + + ILVRL_B2_SB(src7, src6, src76_r, src76_l); + ILVRL_B2_SB(src8, src7, src87_r, src87_l); + ILVRL_B2_SB(src9, src8, src98_r, src98_l); + ILVRL_B2_SB(src10, src9, src109_r, src109_l); + src8776 = (v16i8) __msa_ilvr_d((v2i64) src87_l, (v2i64) src76_l); + src10998 = (v16i8) __msa_ilvr_d((v2i64) src109_l, (v2i64) src98_l); + dst6 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst9 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + dst10 = HEVC_FILT_4TAP_SH(src6554, src8776, filt0, filt1); + dst11 = HEVC_FILT_4TAP_SH(src8776, src10998, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst6, dst7, dst8, dst9, weight_vec, + offset_vec, rnd_vec, dst6, dst7, dst8, + dst9); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst10, dst11, weight_vec, offset_vec, + rnd_vec, dst10, dst11); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST12x4_UB(out3, out4, out5, dst, dst_stride); + dst += (4 * dst_stride); + + src2 = src10; + src10_r = src98_r; + src21_r = src109_r; + src2110 = src10998; } } @@ -3654,25 +3903,33 @@ static void hevc_vt_uniwgt_4t_16w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1, out2, out3; v16i8 src0, src1, src2, src3, src4, src5; v16i8 src10_r, src32_r, src21_r, src43_r; v16i8 src10_l, src32_l, src21_l, src43_l; - v8i16 tmp0, tmp1, tmp2, tmp3; + v16i8 src54_r, src54_l, src65_r, src65_l, src6; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3683,53 +3940,37 @@ static void hevc_vt_uniwgt_4t_16w_msa(uint8_t *src, ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + LD_SB4(src, src_stride, src3, src4, src5, src6); + src += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + ILVRL_B2_SB(src3, src2, src32_r, src32_l); + ILVRL_B2_SB(src4, src3, src43_r, src43_l); + ILVRL_B2_SB(src5, src4, src54_r, src54_l); + ILVRL_B2_SB(src6, src5, src65_r, src65_l); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src32_l, src54_l, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src43_l, src65_l, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + PCKEV_B4_UB(dst4, dst0, dst5, dst1, dst6, dst2, dst7, dst3, out0, out1, + out2, out3); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src10_l, src21_l); - - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src10_l = src54_l; + src21_l = src65_l; } } @@ -3744,113 +3985,94 @@ static void hevc_vt_uniwgt_4t_24w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1, out2, out3, out4, out5; v16i8 src0, src1, src2, src3, src4, src5; - v16i8 src6, src7, src8, src9, src10, src11; - v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - v16i8 src10_l, src32_l, src21_l, src43_l; + v16i8 src6, src7, src8, src9, src10, src11, src12, src13; + v16i8 src10_r, src32_r, src54_r, src21_r, src43_r, src65_r; + v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; + v16i8 src87_r, src98_r, src109_r, src1110_r, src1211_r, src1312_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec, dst11; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); + LD_SB3(src + 16, src_stride, src7, src8, src9); + src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); + XORI_B3_128_SB(src7, src8, src9); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + ILVR_B2_SB(src8, src7, src9, src8, src87_r, src98_r); - LD_SB3(src + 16, src_stride, src6, src7, src8); - src += (3 * src_stride); - XORI_B3_128_SB(src6, src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); + for (loop_cnt = 8; loop_cnt--;) { + LD_SB4(src, src_stride, src3, src4, src5, src6); + LD_SB4(src + 16, src_stride, src10, src11, src12, src13); + src += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + XORI_B4_128_SB(src10, src11, src12, src13); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); - LD_SB2(src + 16, src_stride, src9, src10); - src += (2 * src_stride); - XORI_B2_128_SB(src9, src10); - ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + ILVRL_B2_SB(src5, src4, src54_r, src54_l); + ILVRL_B2_SB(src6, src5, src65_r, src65_l); + ILVR_B2_SB(src10, src9, src11, src10, src109_r, src1110_r); + ILVR_B2_SB(src12, src11, src13, src12, src1211_r, src1312_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src32_l, src54_l, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src43_l, src65_l, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + dst9 = HEVC_FILT_4TAP_SH(src98_r, src1110_r, filt0, filt1); + dst10 = HEVC_FILT_4TAP_SH(src109_r, src1211_r, filt0, filt1); + dst11 = HEVC_FILT_4TAP_SH(src1110_r, src1312_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst8, dst9, dst10, dst11, weight_vec, + offset_vec, rnd_vec, dst8, dst9, dst10, + dst11); + PCKEV_B4_UB(dst4, dst0, dst5, dst1, dst6, dst2, dst7, dst3, out0, out1, + out2, out3); + PCKEV_B2_UB(dst9, dst8, dst11, dst10, out4, out5); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + ST8x4_UB(out4, out5, dst + 16, dst_stride); + dst += (4 * dst_stride); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp2, tmp3, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); - dst += (2 * dst_stride); - - LD_SB2(src, src_stride, src5, src2); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src10_l, src21_l); - LD_SB2(src + 16, src_stride, src11, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src11, src8); - ILVR_B2_SB(src11, src10, src8, src11, src76_r, src87_r); - - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp5, tmp5); - tmp2 = const_vec; - DPADD_SB2_SH(src98_r, src76_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src109_r, src87_r, filt0, filt1, tmp3, tmp3); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp2, tmp3, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); - dst += (2 * dst_stride); + src2 = src6; + src9 = src13; + src10_r = src54_r; + src21_r = src65_r; + src10_l = src54_l; + src21_l = src65_l; + src87_r = src1211_r; + src98_r = src1312_r; } } @@ -3864,104 +4086,87 @@ static void hevc_vt_uniwgt_4t_32w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - int32_t loop_cnt; - uint8_t *dst_tmp = dst + 16; - v16i8 src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v16i8 src21_r, src43_r, src65_r, src87_r; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v16i8 src10_l, src32_l, src76_l, src98_l; - v16i8 src21_l, src43_l, src87_l, src109_l; + v16i8 src21_l, src43_l, src65_l, src87_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l, dst6_l, dst7_l; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); - XORI_B3_128_SB(src0, src1, src2); + LD_SB3(src + 16, src_stride, src5, src6, src7); + src += (3 * src_stride); + XORI_B6_128_SB(src0, src1, src2, src5, src6, src7); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); - - LD_SB3(src + 16, src_stride, src6, src7, src8); - src += (3 * src_stride); - XORI_B3_128_SB(src6, src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); + ILVR_B2_SB(src6, src5, src7, src6, src65_r, src76_r); + ILVL_B2_SB(src6, src5, src7, src6, src65_l, src76_l); for (loop_cnt = (height >> 1); loop_cnt--;) { LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); + LD_SB2(src + 16, src_stride, src8, src9); + src += (2 * src_stride); + XORI_B4_128_SB(src3, src4, src8, src9); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + ILVRL_B2_SB(src8, src7, src87_r, src87_l); + ILVRL_B2_SB(src9, src8, src98_r, src98_l); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src65_l, src87_l, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src76_l, src98_l, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + PCKEV_B4_UB(dst2, dst0, dst3, dst1, dst6, dst4, dst7, dst5, out0, out1, + out2, out3); + ST_UB2(out0, out2, dst, 16); + dst += dst_stride; + ST_UB2(out1, out3, dst, 16); + dst += dst_stride; - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - + src2 = src4; + src7 = src9; src10_r = src32_r; src21_r = src43_r; src10_l = src32_l; src21_l = src43_l; - src2 = src4; - - LD_SB2(src + 16, src_stride, src9, src10); - src += (2 * src_stride); - XORI_B2_128_SB(src9, src10); - ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); - ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); - - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp6 = const_vec; - DPADD_SB2_SH(src76_l, src98_l, filt0, filt1, tmp6, tmp6); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); - tmp7 = const_vec; - DPADD_SB2_SH(src87_l, src109_l, filt0, filt1, tmp7, tmp7); - - HEVC_UNIW_RND_CLIP4(tmp2, tmp3, tmp6, tmp7, - weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst6_r, dst7_r, - dst4_l, dst5_l, dst6_l, dst7_l); - - HEVC_PCK_SW_SB8(dst4_l, dst4_r, dst6_l, dst6_r, - dst5_l, dst5_r, dst7_l, dst7_r, dst4_r, dst5_r); - ST_SW2(dst4_r, dst5_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - + src65_r = src87_r; src76_r = src98_r; - src87_r = src109_r; + src65_l = src87_l; src76_l = src98_l; - src87_l = src109_l; - src8 = src10; } } @@ -3971,22 +4176,20 @@ static void hevc_hv_uniwgt_4t_4x2_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; + v8i16 filt_h0, filt_h1, filter_vec, tmp; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 dst0_r, dst1_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0, dst1, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -3994,63 +4197,41 @@ static void hevc_hv_uniwgt_4t_4x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); - SRAR_W2_SW(dst0_r, dst1_r, rnd_vec); - ADD2(dst0_r, offset_vec, dst1_r, offset_vec, dst0_r, dst1_r); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); - - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + SRAR_W2_SW(dst0, dst1, rnd_vec); + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp += offset_vec; + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, @@ -4059,22 +4240,20 @@ static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec, tmp0, tmp1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst30, dst41, dst52, dst63, dst10, dst32, dst54, dst21, dst43, dst65; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0, dst1, dst2, dst3, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4082,76 +4261,46 @@ static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB4(src, src_stride, src3, src4, src5, src6); - XORI_B4_128_SB(src3, src4, src5, src6); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst2_r, dst3_r, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r); - HEVC_PCK_SW_SB4(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + MUL2(dst2, weight_vec, dst3, weight_vec, dst2, dst3); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, @@ -4166,18 +4315,18 @@ static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v8i16 filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst98_r, dst109_r, offset_vec, const_128, denom_vec; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4185,34 +4334,30 @@ static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src, src_stride, @@ -4220,75 +4365,48 @@ static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, src += (8 * src_stride); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + MUL2(dst2, weight_vec, dst3, weight_vec, dst2, dst3); + MUL2(dst4, weight_vec, dst5, weight_vec, dst4, dst5); + MUL2(dst6, weight_vec, dst7, weight_vec, dst6, dst7); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst54_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - dst65_r = __msa_ilvr_h(dst6, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - dst76_r = __msa_ilvr_h(dst7, dst6); - dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - dst87_r = __msa_ilvr_h(dst8, dst7); - dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst2_r, dst3_r, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r); - HEVC_PCK_SW_SB4(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); - - HEVC_HV_UNIW_RND_CLIP4(dst4_r, dst5_r, dst6_r, dst7_r, - weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst6_r, dst7_r); - HEVC_PCK_SW_SB4(dst5_r, dst4_r, dst7_r, dst6_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -4305,11 +4423,11 @@ static void hevc_hv_uniwgt_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_hv_uniwgt_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x, filter_y, weight, offset, rnd_val); } else if (4 == height) { hevc_hv_uniwgt_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x,filter_y, weight, offset, rnd_val); } else if (0 == (height % 8)) { hevc_hv_uniwgt_4t_4multx8mult_msa(src, src_stride, dst, dst_stride, @@ -4329,20 +4447,22 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst0_l, dst1_r, dst1_l; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v8i16 dst98_l, dst21_l, dst43_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 dst0_l, dst1_l, dst2_l, dst3_l, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4350,20 +4470,20 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); @@ -4371,72 +4491,78 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src, src_stride, src3, src4, src5, src6); - src += (4 * src_stride); - XORI_B4_128_SB(src3, src4, src5, src6); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_HV_UNIW_RND_CLIP4(dst2_r, dst3_r, dst2_l, dst3_l, - weight_vec, offset_vec, rnd_vec, - dst2_r, dst3_r, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst4_r, weight_vec, dst5_r, weight_vec, dst4_r, dst5_r); + MUL2(dst6_r, weight_vec, dst7_r, weight_vec, dst6_r, dst7_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, rnd_vec); + SRAR_W4_SW(dst4_r, dst5_r, dst6_r, dst7_r, rnd_vec); + SRAR_W4_SW(dst0_l, dst1_l, dst2_l, dst3_l, rnd_vec); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + ADD2(tmp4, offset_vec, tmp5, offset_vec, tmp4, tmp5); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + PCKEV_B3_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, out0, out1, out2); + ST4x8_UB(out0, out1, dst, dst_stride); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, @@ -4445,23 +4571,24 @@ static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1; + v8i16 offset_vec, const_128, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4469,65 +4596,144 @@ static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst, dst_stride); +} - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); +static void hevc_hv_uniwgt_4t_8multx4_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t width8mult, + int32_t weight, + int32_t offset, + int32_t rnd_val) +{ + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 weight_vec, rnd_vec; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + for (cnt = width8mult; cnt--;) { + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, @@ -4536,26 +4742,27 @@ static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v4i32 dst4_r, dst4_l, dst5_r, dst5_l; + v4i32 dst4_r, dst4_l, dst5_r, dst5_l, weight_vec, rnd_vec; v8i16 dst10_r, dst32_r, dst10_l, dst32_l; v8i16 dst21_r, dst43_r, dst21_l, dst43_l; v8i16 dst54_r, dst54_l, dst65_r, dst65_l; v8i16 dst76_r, dst76_l, dst87_r, dst87_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 offset_vec, const_128, denom_vec; src -= (src_stride + 1); @@ -4563,126 +4770,87 @@ static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + src += (5 * src_stride); + LD_SB4(src, src_stride, src5, src6, src7, src8); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src6); - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src7, src8); - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - - dst4_r >>= 6; - dst4_l >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_HV_UNIW_RND_CLIP4(dst2_r, dst3_r, dst2_l, dst3_l, - weight_vec, offset_vec, rnd_vec, - dst2_r, dst3_r, dst2_l, dst3_l); - HEVC_HV_UNIW_RND_CLIP4(dst4_r, dst5_r, dst4_l, dst5_l, - weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst4_r, weight_vec, dst5_r, weight_vec, dst4_r, dst5_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + MUL2(dst4_l, weight_vec, dst5_l, weight_vec, dst4_l, dst5_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + SRAR_W4_SW(dst4_r, dst4_l, dst5_r, dst5_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, + tmp0, tmp1, tmp2, tmp3); + PCKEV_H2_SH(dst4_l, dst4_r, dst5_l, dst5_r, tmp4, tmp5); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + ADD2(tmp4, offset_vec, tmp5, offset_vec, tmp4, tmp5); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + PCKEV_B3_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, @@ -4695,24 +4863,25 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, int32_t weight, int32_t offset, int32_t rnd_val, - int32_t width) + int32_t width8mult) { uint32_t loop_cnt, cnt; uint8_t *src_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 offset_vec, const_128, denom_vec; v4i32 dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v4i32 weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4720,21 +4889,21 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - for (cnt = width >> 3; cnt--;) { + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + for (cnt = width8mult; cnt--;) { src_tmp = src; dst_tmp = dst; @@ -4745,12 +4914,9 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); @@ -4761,51 +4927,47 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, XORI_B4_128_SB(src3, src4, src5, src6); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_HV_UNIW_RND_CLIP4(dst2_r, dst3_r, dst2_l, dst3_l, - weight_vec, offset_vec, rnd_vec, - dst2_r, dst3_r, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst_tmp, dst_stride); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src += 8; @@ -4827,16 +4989,20 @@ static void hevc_hv_uniwgt_4t_8w_msa(uint8_t *src, if (2 == height) { hevc_hv_uniwgt_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x, filter_y, weight, offset, rnd_val); + } else if (4 == height) { + hevc_hv_uniwgt_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 1, weight, + offset, rnd_val); } else if (6 == height) { hevc_hv_uniwgt_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x, filter_y, weight, offset, rnd_val); } else if (0 == (height % 4)) { hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, weight, - offset, rnd_val, 8); + offset, rnd_val, 1); } } @@ -4851,12 +5017,170 @@ static void hevc_hv_uniwgt_4t_12w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val, 8); - hevc_hv_uniwgt_4t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, weight_vec, rnd_vec; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + src_tmp = src; + dst_tmp = dst; + + LD_SB3(src_tmp, src_stride, src0, src1, src2); + src_tmp += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src += 8; + dst += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + MUL2(dst2, weight_vec, dst3, weight_vec, dst2, dst3); + MUL2(dst4, weight_vec, dst5, weight_vec, dst4, dst5); + MUL2(dst6, weight_vec, dst7, weight_vec, dst6, dst7); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_uniwgt_4t_16w_msa(uint8_t *src, @@ -4870,9 +5194,15 @@ static void hevc_hv_uniwgt_4t_16w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val, 16); + if (4 == height) { + hevc_hv_uniwgt_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 2, weight, offset, + rnd_val); + } else { + hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, weight, + offset, rnd_val, 2); + } } static void hevc_hv_uniwgt_4t_24w_msa(uint8_t *src, @@ -4888,7 +5218,7 @@ static void hevc_hv_uniwgt_4t_24w_msa(uint8_t *src, { hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, weight, - offset, rnd_val, 24); + offset, rnd_val, 3); } static void hevc_hv_uniwgt_4t_32w_msa(uint8_t *src, @@ -4904,7 +5234,7 @@ static void hevc_hv_uniwgt_4t_32w_msa(uint8_t *src, { hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, weight, - offset, rnd_val, 32); + offset, rnd_val, 4); } #define UNIWGT_MC_COPY(WIDTH) \ @@ -4939,18 +5269,18 @@ UNIWGT_MC_COPY(64); #define UNI_W_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ void ff_hevc_put_hevc_uni_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - int denom, \ - int weight, \ - int offset, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ + ptrdiff_t \ + dst_stride, \ + uint8_t *src, \ + ptrdiff_t \ + src_stride, \ + int height, \ + int denom, \ + int weight, \ + int offset, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ { \ const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ int shift = denom + 14 - 8; \ @@ -4996,46 +5326,43 @@ UNI_W_MC(epel, v, 32, 4, vt, my); #undef UNI_W_MC -#define UNI_W_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_uni_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - int denom, \ - int weight, \ - int offset, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - int shift = denom + 14 - 8; \ - \ - hevc_##DIR1##_uniwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ - dst_stride, filter_x, \ - filter_y, height, weight, \ - offset, shift); \ +#define UNI_W_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_uni_w_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + int denom, \ + int weight, \ + int offset, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + int shift = denom + 14 - 8; \ + \ + hevc_hv_uniwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, dst_stride, \ + filter_x, filter_y, height, \ + weight, offset, shift); \ } -UNI_W_MC_HV(qpel, hv, 4, 8, hv); -UNI_W_MC_HV(qpel, hv, 8, 8, hv); -UNI_W_MC_HV(qpel, hv, 12, 8, hv); -UNI_W_MC_HV(qpel, hv, 16, 8, hv); -UNI_W_MC_HV(qpel, hv, 24, 8, hv); -UNI_W_MC_HV(qpel, hv, 32, 8, hv); -UNI_W_MC_HV(qpel, hv, 48, 8, hv); -UNI_W_MC_HV(qpel, hv, 64, 8, hv); +UNI_W_MC_HV(qpel, 4, 8); +UNI_W_MC_HV(qpel, 8, 8); +UNI_W_MC_HV(qpel, 12, 8); +UNI_W_MC_HV(qpel, 16, 8); +UNI_W_MC_HV(qpel, 24, 8); +UNI_W_MC_HV(qpel, 32, 8); +UNI_W_MC_HV(qpel, 48, 8); +UNI_W_MC_HV(qpel, 64, 8); -UNI_W_MC_HV(epel, hv, 4, 4, hv); -UNI_W_MC_HV(epel, hv, 6, 4, hv); -UNI_W_MC_HV(epel, hv, 8, 4, hv); -UNI_W_MC_HV(epel, hv, 12, 4, hv); -UNI_W_MC_HV(epel, hv, 16, 4, hv); -UNI_W_MC_HV(epel, hv, 24, 4, hv); -UNI_W_MC_HV(epel, hv, 32, 4, hv); +UNI_W_MC_HV(epel, 4, 4); +UNI_W_MC_HV(epel, 6, 4); +UNI_W_MC_HV(epel, 8, 4); +UNI_W_MC_HV(epel, 12, 4); +UNI_W_MC_HV(epel, 16, 4); +UNI_W_MC_HV(epel, 24, 4); +UNI_W_MC_HV(epel, 32, 4); #undef UNI_W_MC_HV diff --git a/libavcodec/mips/hevcdsp_msa.c b/libavcodec/mips/hevcdsp_msa.c index 73cc3ea21..81db62b87 100644 --- a/libavcodec/mips/hevcdsp_msa.c +++ b/libavcodec/mips/hevcdsp_msa.c @@ -22,6 +22,13 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + /* 4 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 +}; + static void hevc_copy_4w_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, int32_t height) @@ -449,7 +456,7 @@ static void hevc_hz_8t_4w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 3; const_vec = __msa_ldi_h(128); @@ -504,7 +511,7 @@ static void hevc_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; const_vec = __msa_ldi_h(128); @@ -552,8 +559,75 @@ static void hevc_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - hevc_hz_8t_8w_msa(src, src_stride, dst, dst_stride, filter, height); - hevc_hz_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, filter, height); + uint32_t loop_cnt; + int64_t res0, res1, res2, res3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 filt0, filt1, filt2, filt3, dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filter_vec, const_vec; + + src -= 3; + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + filter_vec = LD_SH(filter); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, src_stride, src0, src1, src2, src3); + LD_SB4(src + 8, src_stride, src4, src5, src6, src7); + src += (4 * src_stride); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask4, mask4, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask5, mask5, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask6, mask6, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask7, mask7, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt3, filt3, dst4, dst5); + + res0 = __msa_copy_s_d((v2i64) dst4, 0); + res1 = __msa_copy_s_d((v2i64) dst4, 1); + res2 = __msa_copy_s_d((v2i64) dst5, 0); + res3 = __msa_copy_s_d((v2i64) dst5, 1); + ST_SH4(dst0, dst1, dst2, dst3, dst, dst_stride); + SD4(res0, res1, res2, res3, (dst + 8), dst_stride); + dst += (4 * dst_stride); + } } static void hevc_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, @@ -561,13 +635,13 @@ static void hevc_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 src0, src1, src2, src3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3; v16i8 vec0, vec1, vec2, vec3; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; const_vec = __msa_ldi_h(128); @@ -580,56 +654,36 @@ static void hevc_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, mask2 = mask0 + 4; mask3 = mask0 + 6; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src2, src4, src6); - LD_SB4(src + 8, src_stride, src1, src3, src5, src7); - src += (4 * src_stride); - XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src, src_stride, src0, src2); + LD_SB2(src + 8, src_stride, src1, src3); + src += (2 * src_stride); + XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); - VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst6 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); - ST_SH4(dst0, dst2, dst4, dst6, dst, dst_stride); - ST_SH4(dst1, dst3, dst5, dst7, dst + 8, dst_stride); - dst += (4 * dst_stride); + ST_SH2(dst0, dst2, dst, dst_stride); + ST_SH2(dst1, dst3, dst + 8, dst_stride); + dst += (2 * dst_stride); } } @@ -641,10 +695,10 @@ static void hevc_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; - v16i8 vec0, vec1, vec2, vec3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; filter_vec = LD_SH(filter); @@ -668,36 +722,36 @@ static void hevc_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); - VSHF_B4_SB(src2, src3, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask4, mask0, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask5, mask1, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask6, mask2, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, dst4, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask7, mask3, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt3, filt3, dst4, dst5); ST_SH2(dst0, dst1, dst, 8); ST_SH(dst2, dst + 16); @@ -719,7 +773,7 @@ static void hevc_hz_8t_32w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; filter_vec = LD_SH(filter); @@ -776,10 +830,10 @@ static void hevc_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; - v16i8 vec0, vec1, vec2, vec3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; filter_vec = LD_SH(filter); @@ -802,38 +856,39 @@ static void hevc_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src1, src2, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask0, mask4, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask1, mask5, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask2, mask6, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask3, mask7, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + ST_SH4(dst0, dst1, dst2, dst3, dst, 8); - ST_SH6(dst0, dst1, dst2, dst3, dst4, dst5, dst, 8); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt3, filt3, dst4, dst5); + ST_SH2(dst4, dst5, (dst + 32), 8); dst += dst_stride; } } @@ -849,7 +904,7 @@ static void hevc_hz_8t_64w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; @@ -1308,31 +1363,28 @@ static void hevc_hv_8t_4w_msa(uint8_t *src, int32_t src_stride, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + int32_t dst_stride_in_bytes = 2 * dst_stride; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { - 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 - }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1364,47 +1416,56 @@ static void hevc_hv_8t_4w_msa(uint8_t *src, int32_t src_stride, DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, dst63, dst63, dst63, dst63); - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src7, src8); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = const_vec; + dst108 = const_vec; DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); + dst97, dst97, dst97, dst97); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, + dst108, dst108, dst108, dst108); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, filt_h1, filt_h2, filt_h3); - dst0_r >>= 6; - dst1_r >>= 6; + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, + filt_h0, filt_h1, filt_h2, filt_h3); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst2_r); + ST8x4_UB(dst0_r, dst2_r, dst, dst_stride_in_bytes); + dst += (4 * dst_stride); - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - ST8x2_UB(dst0_r, dst, (2 * dst_stride)); - dst += (2 * dst_stride); - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } -static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, +static void hevc_hv_8t_8multx1mult_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, @@ -1415,19 +1476,17 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, uint32_t loop_cnt, cnt; uint8_t *src_tmp; int16_t *dst_tmp; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v4i32 dst0_r, dst0_l; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst10_l, dst32_l, dst54_l, dst76_l; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v8i16 dst21_l, dst43_l, dst65_l, dst87_l; v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; src -= ((3 * src_stride) + 3); @@ -1435,10 +1494,9 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1494,17 +1552,10 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst6, dst6, dst6, dst6); - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); - - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src_tmp, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - src_tmp += 2 * src_stride; + for (loop_cnt = height; loop_cnt--;) { + src7 = LD_SB(src_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src_tmp += src_stride; VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1512,6 +1563,9 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst7, dst7, dst7, dst7); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, filt_h1, filt_h2, filt_h3); @@ -1524,37 +1578,13 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, ST_SW(dst0_r, dst_tmp); dst_tmp += dst_stride; - VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); - dst6 = dst8; - dst0_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst0_l = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, - filt_h0, filt_h1, filt_h2, filt_h3); - dst0_r >>= 6; - dst0_l >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - ST_SW(dst0_r, dst_tmp); - dst_tmp += dst_stride; - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; } src += 8; @@ -1567,7 +1597,7 @@ static void hevc_hv_8t_8w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 8); } @@ -1576,11 +1606,195 @@ static void hevc_hv_8t_12w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + int32_t dst_stride_in_bytes = 2 * dst_stride; + uint8_t *src_tmp; + int16_t *dst_tmp; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v4i32 dst0_r, dst0_l, dst1_r, dst2_r, dst3_r; - hevc_hv_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + src -= ((3 * src_stride) + 3); + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst0, dst0, + dst0, dst0); + dst1 = const_vec; + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst1, dst1, + dst1, dst1); + dst2 = const_vec; + DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst2, + dst2, dst2, dst2); + dst3 = const_vec; + DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, dst3, + dst3, dst3, dst3); + + /* row 4 row 5 row 6 */ + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst4, dst4, + dst4, dst4); + dst5 = const_vec; + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst5, dst5, + dst5, dst5); + dst6 = const_vec; + DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst6, + dst6, dst6, dst6); + + for (loop_cnt = height; loop_cnt--;) { + src7 = LD_SB(src_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src_tmp += src_stride; + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst7, + dst7, dst7, dst7); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + ST_SW(dst0_r, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; + } + + src += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + dst30 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst30, + dst30, dst30, dst30); + dst41 = const_vec; + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst41, + dst41, dst41, dst41); + dst52 = const_vec; + DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst52, + dst52, dst52, dst52); + dst63 = const_vec; + DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, dst63, + dst63, dst63, dst63); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = const_vec; + dst108 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst97, + dst97, dst97, dst97); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst108, + dst108, dst108, dst108); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst2_r); + ST8x4_UB(dst0_r, dst2_r, dst, dst_stride_in_bytes); + dst += (4 * dst_stride); + + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_8t_16w_msa(uint8_t *src, int32_t src_stride, @@ -1588,7 +1802,7 @@ static void hevc_hv_8t_16w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 16); } @@ -1597,7 +1811,7 @@ static void hevc_hv_8t_24w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 24); } @@ -1606,7 +1820,7 @@ static void hevc_hv_8t_32w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 32); } @@ -1615,7 +1829,7 @@ static void hevc_hv_8t_48w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 48); } @@ -1624,7 +1838,7 @@ static void hevc_hv_8t_64w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 64); } @@ -1639,7 +1853,7 @@ static void hevc_hz_4t_4x2_msa(uint8_t *src, v16i8 mask1, vec0, vec1; v8i16 dst0; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 1; @@ -1672,7 +1886,7 @@ static void hevc_hz_4t_4x4_msa(uint8_t *src, v16i8 mask1, vec0, vec1; v8i16 dst0, dst1; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 1; @@ -1711,7 +1925,7 @@ static void hevc_hz_4t_4x8multiple_msa(uint8_t *src, v16i8 mask1, vec0, vec1; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 1; @@ -1776,7 +1990,7 @@ static void hevc_hz_4t_6w_msa(uint8_t *src, uint32_t dst_val_int0, dst_val_int1, dst_val_int2, dst_val_int3; v8i16 filt0, filt1, dst0, dst1, dst2, dst3; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 filter_vec, const_vec; @@ -1791,7 +2005,7 @@ static void hevc_hz_4t_6w_msa(uint8_t *src, const_vec = __msa_ldi_h(128); const_vec <<= 6; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 2; loop_cnt--;) { LD_SB4(src, src_stride, src0, src1, src2, src3); src += (4 * src_stride); @@ -1845,7 +2059,7 @@ static void hevc_hz_4t_8x2multiple_msa(uint8_t *src, uint32_t loop_cnt; v8i16 filt0, filt1, dst0, dst1; v16i8 src0, src1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 filter_vec, const_vec; @@ -1889,7 +2103,7 @@ static void hevc_hz_4t_8x4multiple_msa(uint8_t *src, uint32_t loop_cnt; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; @@ -1963,7 +2177,7 @@ static void hevc_hz_4t_12w_msa(uint8_t *src, v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; v16i8 mask3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; @@ -2020,7 +2234,7 @@ static void hevc_hz_4t_16w_msa(uint8_t *src, v16i8 src0, src1, src2, src3; v16i8 src4, src5, src6, src7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v16i8 vec0, vec1; @@ -2092,7 +2306,7 @@ static void hevc_hz_4t_24w_msa(uint8_t *src, int16_t *dst_tmp = dst + 16; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask00, mask11; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; @@ -2192,10 +2406,10 @@ static void hevc_hz_4t_32w_msa(uint8_t *src, uint32_t loop_cnt; v16i8 src0, src1, src2; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask2, mask3; v8i16 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 filter_vec, const_vec; src -= 1; @@ -2210,54 +2424,25 @@ static void hevc_hz_4t_32w_msa(uint8_t *src, mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = height; loop_cnt--;) { LD_SB2(src, 16, src0, src1); src2 = LD_SB(src + 24); src += src_stride; XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - ST_SH4(dst0, dst1, dst2, dst3, dst, 8); - dst += dst_stride; - - LD_SB2(src, 16, src0, src1); - src2 = LD_SB(src + 24); - src += src_stride; - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); ST_SH4(dst0, dst1, dst2, dst3, dst, 8); dst += dst_stride; } @@ -2333,18 +2518,17 @@ static void hevc_vt_4t_4x4_msa(uint8_t *src, ST8x4_UB(dst10, dst32, dst, 2 * dst_stride); } -static void hevc_vt_4t_4x8multiple_msa(uint8_t *src, - int32_t src_stride, - int16_t *dst, - int32_t dst_stride, - const int8_t *filter, - int32_t height) +static void hevc_vt_4t_4x8_msa(uint8_t *src, + int32_t src_stride, + int16_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t height) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; - v16i8 src2110, src4332, src6554, src8776; + v16i8 src2110, src4332, src6554, src8776, src10998; v8i16 dst10, dst32, dst54, dst76; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2363,35 +2547,96 @@ static void hevc_vt_4t_4x8multiple_msa(uint8_t *src, src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); - src += (6 * src_stride); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, + src32_r, src43_r, src54_r, src65_r); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, + src76_r, src87_r, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, src109_r, + src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + dst10 = const_vec; + dst32 = const_vec; + dst54 = const_vec; + dst76 = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); + ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + dst += (8 * dst_stride); +} - ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, - src32_r, src43_r, src54_r, src65_r); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVR_D3_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, - src4332, src6554, src8776); - XORI_B3_128_SB(src4332, src6554, src8776); +static void hevc_vt_4t_4x16_msa(uint8_t *src, int32_t src_stride, + int16_t *dst, int32_t dst_stride, + const int8_t *filter, int32_t height) +{ + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src10_r, src32_r, src54_r, src76_r, src98_r, src21_r, src43_r; + v16i8 src65_r, src87_r, src109_r, src2110, src4332, src6554, src8776; + v16i8 src10998; + v8i16 dst10, dst32, dst54, dst76, filt0, filt1, filter_vec, const_vec; - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - dst54 = const_vec; - DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + src -= src_stride; + const_vec = __msa_ldi_h(128); + const_vec <<= 6; - LD_SB2(src, src_stride, src9, src2); - src += (2 * src_stride); - ILVR_B2_SB(src9, src8, src2, src9, src98_r, src109_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src109_r, (v2i64) src98_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - dst76 = const_vec; - DPADD_SB2_SH(src8776, src2110, filt0, filt1, dst76, dst76); + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); - dst += (8 * dst_stride); - } + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); + src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); + + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, + src54_r, src65_r); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, src109_r, + src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + + dst10 = const_vec; + dst32 = const_vec; + dst54 = const_vec; + dst76 = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); + ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + dst += (8 * dst_stride); + + src2 = src10; + src2110 = src10998; + + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + + ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, + src54_r, src65_r); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, src109_r, + src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + + dst10 = const_vec; + dst32 = const_vec; + dst54 = const_vec; + dst76 = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); + ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + dst += (8 * dst_stride); } static void hevc_vt_4t_4w_msa(uint8_t *src, @@ -2405,9 +2650,10 @@ static void hevc_vt_4t_4w_msa(uint8_t *src, hevc_vt_4t_4x2_msa(src, src_stride, dst, dst_stride, filter); } else if (4 == height) { hevc_vt_4t_4x4_msa(src, src_stride, dst, dst_stride, filter, height); - } else if (0 == (height % 8)) { - hevc_vt_4t_4x8multiple_msa(src, src_stride, dst, dst_stride, - filter, height); + } else if (8 == height) { + hevc_vt_4t_4x8_msa(src, src_stride, dst, dst_stride, filter, height); + } else if (16 == height) { + hevc_vt_4t_4x16_msa(src, src_stride, dst, dst_stride, filter, height); } } @@ -2590,9 +2836,9 @@ static void hevc_vt_4t_8x4multiple_msa(uint8_t *src, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; - v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 dst0_r, dst1_r; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2609,29 +2855,25 @@ static void hevc_vt_4t_8x4multiple_msa(uint8_t *src, ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); + LD_SB4(src, src_stride, src3, src4, src5, src6); + src += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); dst0_r = const_vec; + dst1_r = const_vec; + dst2_r = const_vec; + dst3_r = const_vec; DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); - dst1_r = const_vec; DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); + ST_SH4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); + dst += (4 * dst_stride); - ST_SH2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - dst0_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst0_r, dst0_r); - dst1_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst1_r, dst1_r); - - ST_SH2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; } } @@ -2660,11 +2902,12 @@ static void hevc_vt_4t_12w_msa(uint8_t *src, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16i8 src0, src1, src2, src3, src4, src5, src6; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; v16i8 src2110, src4332; + v16i8 src54_r, src65_r, src6554; v8i16 dst0_l, dst1_l; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2683,36 +2926,42 @@ static void hevc_vt_4t_12w_msa(uint8_t *src, ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_l, (v2i64) src10_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB2(src, src_stride, src3, src4); src += (2 * src_stride); + LD_SB2(src, src_stride, src5, src6); + src += (2 * src_stride); XORI_B2_128_SB(src3, src4); + XORI_B2_128_SB(src5, src6); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVL_B2_SB(src5, src4, src6, src5, src54_l, src65_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); + dst0_r = const_vec; DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); dst1_r = const_vec; DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); + dst2_r = const_vec; + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + dst3_r = const_vec; + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); dst0_l = const_vec; DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst0_l, dst0_l); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - dst2_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst2_r, dst2_r); - dst3_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst3_r, dst3_r); dst1_l = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, dst1_l, dst1_l); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst1_l, dst1_l); ST_SH4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); ST8x4_UB(dst0_l, dst1_l, dst + 8, (2 * dst_stride)); dst += (4 * dst_stride); + + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src2110 = src6554; } } @@ -2994,69 +3243,52 @@ static void hevc_hv_4t_4x2_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y) { + int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43; + v4i32 dst0, dst1; src -= (src_stride + 1); filter_vec = LD_SH(filter_x); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + dst20 = const_vec; + dst31 = const_vec; + dst42 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst20, dst20); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst31, dst31); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst42, dst42); + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - ST8x2_UB(dst0_r, dst, 2 * dst_stride); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + dst0 = (v4i32) __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + ST8x2_UB(dst0, dst, dst_stride_in_bytes); } static void hevc_hv_4t_4x4_msa(uint8_t *src, @@ -3066,16 +3298,16 @@ static void hevc_hv_4t_4x4_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y) { + int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst30, dst41, dst52, dst63, dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 dst0, dst1, dst2, dst3; src -= (src_stride + 1); @@ -3083,71 +3315,43 @@ static void hevc_hv_4t_4x4_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + dst30 = const_vec; + dst41 = const_vec; + dst52 = const_vec; + dst63 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst30, dst30); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst41, dst41); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst52, dst52); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst63, dst63); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB4(src, src_stride, src3, src4, src5, src6); - XORI_B4_128_SB(src3, src4, src5, src6); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - - PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, 2 * dst_stride); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SW(dst1, dst0, dst3, dst2, dst0, dst2); + ST8x4_UB(dst0, dst2, dst, dst_stride_in_bytes); } @@ -3163,25 +3367,24 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, v16i8 src0, src1, src2, src3, src4, src5, src6; v16i8 src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; src -= (src_stride + 1); filter_vec = LD_SH(filter_x); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3191,19 +3394,14 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst10, dst10); + dst21 = const_vec; + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst21, dst21); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src, src_stride, @@ -3211,75 +3409,45 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, src += (8 * src_stride); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; + dst73 = const_vec; + dst84 = const_vec; + dst95 = const_vec; + dst106 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst73, dst73); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst84, dst84); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst95, dst95); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst106, dst106); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst54_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - dst65_r = __msa_ilvr_h(dst6, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - dst76_r = __msa_ilvr_h(dst7, dst6); - dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - dst87_r = __msa_ilvr_h(dst8, dst7); - dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - - PCKEV_H4_SW(dst1_r, dst0_r, dst3_r, dst2_r, - dst5_r, dst4_r, dst7_r, dst6_r, - dst0_r, dst1_r, dst2_r, dst3_r); - ST8x8_UB(dst0_r, dst1_r, dst2_r, dst3_r, dst, 2 * dst_stride); + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + dst0, dst1, dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, 2 * dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -3311,30 +3479,31 @@ static void hevc_hv_4t_6w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - uint32_t loop_cnt; - uint64_t dst_val0, dst_val1, dst_val2, dst_val3; - uint32_t dst_val_int0, dst_val_int1, dst_val_int2, dst_val_int3; - v16i8 src0, src1, src2, src3, src4, src5, src6; + int32_t dst_stride_in_bytes = 2 * dst_stride; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v8i16 dst98_l, dst21_l, dst43_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 dst0_l, dst1_l, dst2_l, dst3_l; src -= (src_stride + 1); filter_vec = LD_SH(filter_x); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3349,89 +3518,83 @@ static void hevc_hv_4t_6w_msa(uint8_t *src, VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = const_vec; + dsth1 = const_vec; + dsth2 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dsth0, dsth0); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dsth1, dsth1); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dsth2, dsth2); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src, src_stride, src3, src4, src5, src6); - src += (4 * src_stride); - XORI_B4_128_SB(src3, src4, src5, src6); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + dsth3 = const_vec; + dsth4 = const_vec; + dsth5 = const_vec; + dsth6 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dsth3, dsth3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dsth4, dsth4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dsth5, dsth5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dsth6, dsth6); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dsth7 = const_vec; + dsth8 = const_vec; + dsth9 = const_vec; + dsth10 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dsth7, dsth7); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dsth8, dsth8); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dsth9, dsth9); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dsth10, dsth10); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst0_r, dst1_r, dst2_r, dst3_r); - - dst_val0 = __msa_copy_u_d((v2i64) dst0_r, 0); - dst_val1 = __msa_copy_u_d((v2i64) dst1_r, 0); - dst_val2 = __msa_copy_u_d((v2i64) dst2_r, 0); - dst_val3 = __msa_copy_u_d((v2i64) dst3_r, 0); - - dst_val_int0 = __msa_copy_u_w((v4i32) dst0_r, 2); - dst_val_int1 = __msa_copy_u_w((v4i32) dst1_r, 2); - dst_val_int2 = __msa_copy_u_w((v4i32) dst2_r, 2); - dst_val_int3 = __msa_copy_u_w((v4i32) dst3_r, 2); - - SD(dst_val0, dst); - SW(dst_val_int0, dst + 4); - dst += dst_stride; - SD(dst_val1, dst); - SW(dst_val_int1, dst + 4); - dst += dst_stride; - SD(dst_val2, dst); - SW(dst_val_int2, dst + 4); - dst += dst_stride; - SD(dst_val3, dst); - SW(dst_val_int3, dst + 4); - dst += dst_stride; - - } + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + ST8x4_UB(tmp0, tmp1, dst, dst_stride_in_bytes); + ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, dst + 4, dst_stride_in_bytes); + dst += 4 * dst_stride; + ST8x4_UB(tmp2, tmp3, dst, dst_stride_in_bytes); + ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, dst + 4, dst_stride_in_bytes); } static void hevc_hv_4t_8x2_msa(uint8_t *src, @@ -3439,16 +3602,15 @@ static void hevc_hv_4t_8x2_msa(uint8_t *src, int16_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; @@ -3460,23 +3622,23 @@ static void hevc_hv_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); dst0 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); @@ -3484,53 +3646,123 @@ static void hevc_hv_4t_8x2_msa(uint8_t *src, DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); dst2 = const_vec; DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst3 = const_vec; + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst3, dst3); + dst4 = const_vec; + DPADD_SB2_SH(vec8, vec9, filt0, filt1, dst4, dst4); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); ST_SW2(dst0_r, dst1_r, dst, dst_stride); } +static void hevc_hv_4t_8multx4_msa(uint8_t *src, int32_t src_stride, + int16_t *dst, int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, int32_t width8mult) +{ + int32_t cnt; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + for (cnt = width8mult; cnt--;) { + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + dst6 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst4, dst4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst5, dst5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst6, dst6); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); + PCKEV_H2_SW(dst2_l, dst2_r, dst3_l, dst3_r, dst2_r, dst3_r); + + ST_SW4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); + dst += 8; + } +} + static void hevc_hv_4t_8x6_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v4i32 dst4_r, dst4_l, dst5_r, dst5_l; @@ -3545,24 +3777,31 @@ static void hevc_hv_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + src += (5 * src_stride); + LD_SB4(src, src_stride, src5, src6, src7, src8); - XORI_B3_128_SB(src0, src1, src2); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); dst0 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); @@ -3570,91 +3809,44 @@ static void hevc_hv_4t_8x6_msa(uint8_t *src, DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); dst2 = const_vec; DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst3 = const_vec; + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst3, dst3); + dst4 = const_vec; + DPADD_SB2_SH(vec8, vec9, filt0, filt1, dst4, dst4); + dst5 = const_vec; + DPADD_SB2_SH(vec10, vec11, filt0, filt1, dst5, dst5); + dst6 = const_vec; + DPADD_SB2_SH(vec12, vec13, filt0, filt1, dst6, dst6); + dst7 = const_vec; + DPADD_SB2_SH(vec14, vec15, filt0, filt1, dst7, dst7); + dst8 = const_vec; + DPADD_SB2_SH(vec16, vec17, filt0, filt1, dst8, dst8); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - - XORI_B2_128_SB(src5, src6); - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - LD_SB2(src, src_stride, src7, src8); - - XORI_B2_128_SB(src7, src8); - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - dst4_r >>= 6; - dst4_l >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); @@ -3674,22 +3866,22 @@ static void hevc_hv_4t_8multx4mult_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y, int32_t height, - int32_t width) + int32_t width8mult) { uint32_t loop_cnt, cnt; uint8_t *src_tmp; int16_t *dst_tmp; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; src -= (src_stride + 1); @@ -3697,17 +3889,16 @@ static void hevc_hv_4t_8multx4mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - for (cnt = width >> 3; cnt--;) { + for (cnt = width8mult; cnt--;) { src_tmp = src; dst_tmp = dst; @@ -3736,59 +3927,48 @@ static void hevc_hv_4t_8multx4mult_msa(uint8_t *src, XORI_B4_128_SB(src3, src4, src5, src6); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + dst6 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst4, dst4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst5, dst5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst6, dst6); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - - dst3_r >>= 6; - dst3_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - ST_SW2(dst2_r, dst3_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + ST_SW4(dst0_r, dst1_r, dst2_r, dst3_r, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src += 8; @@ -3807,13 +3987,16 @@ static void hevc_hv_4t_8w_msa(uint8_t *src, if (2 == height) { hevc_hv_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); + } else if (4 == height) { + hevc_hv_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (0 == (height % 4)) { hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + filter_x, filter_y, height, 1); } } @@ -3825,12 +4008,169 @@ static void hevc_hv_4t_12w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + uint8_t *src_tmp; + int16_t *dst_tmp; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst10, dst21, dst22, dst73; + v8i16 dst84, dst95, dst106, dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - hevc_hv_4t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + src -= (src_stride + 1); + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB3(src_tmp, src_stride, src0, src1, src2); + src_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + dst6 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst4, dst4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst5, dst5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst6, dst6); + + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); + ST_SW4(dst0_r, dst1_r, dst2_r, dst3_r, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; + } + + src += 8; + dst += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + dst10 = const_vec; + dst21 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst21, dst21); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = const_vec; + dst84 = const_vec; + dst95 = const_vec; + dst106 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst73, dst73); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst84, dst84); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst95, dst95); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst106, dst106); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + tmp0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + tmp1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + tmp2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + tmp3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + tmp4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + tmp5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + tmp6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + tmp7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + + SRA_4V(tmp0, tmp1, tmp2, tmp3, 6); + SRA_4V(tmp4, tmp5, tmp6, tmp7, 6); + PCKEV_H4_SW(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, tmp0, tmp1, + tmp2, tmp3); + ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, 2 * dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_4t_16w_msa(uint8_t *src, @@ -3841,8 +4181,13 @@ static void hevc_hv_4t_16w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 16); + if (4 == height) { + hevc_hv_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 2); + } else { + hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 2); + } } static void hevc_hv_4t_24w_msa(uint8_t *src, @@ -3854,7 +4199,7 @@ static void hevc_hv_4t_24w_msa(uint8_t *src, int32_t height) { hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 24); + filter_x, filter_y, height, 3); } static void hevc_hv_4t_32w_msa(uint8_t *src, @@ -3866,7 +4211,7 @@ static void hevc_hv_4t_32w_msa(uint8_t *src, int32_t height) { hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 32); + filter_x, filter_y, height, 4); } #define MC_COPY(WIDTH) \ @@ -3893,19 +4238,19 @@ MC_COPY(64); #undef MC_COPY -#define MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ -void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ - \ - hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ - MAX_PB_SIZE, filter, height); \ +#define MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ +void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ + \ + hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ + MAX_PB_SIZE, filter, height); \ } MC(qpel, h, 4, 8, hz, mx); @@ -3944,37 +4289,37 @@ MC(epel, v, 32, 4, vt, my); #undef MC -#define MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, MAX_PB_SIZE, \ - filter_x, filter_y, height); \ +#define MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_##PEL##_hv##WIDTH##_8_msa(int16_t *dst, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + \ + hevc_hv_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, MAX_PB_SIZE, \ + filter_x, filter_y, height); \ } -MC_HV(qpel, hv, 4, 8, hv); -MC_HV(qpel, hv, 8, 8, hv); -MC_HV(qpel, hv, 12, 8, hv); -MC_HV(qpel, hv, 16, 8, hv); -MC_HV(qpel, hv, 24, 8, hv); -MC_HV(qpel, hv, 32, 8, hv); -MC_HV(qpel, hv, 48, 8, hv); -MC_HV(qpel, hv, 64, 8, hv); +MC_HV(qpel, 4, 8); +MC_HV(qpel, 8, 8); +MC_HV(qpel, 12, 8); +MC_HV(qpel, 16, 8); +MC_HV(qpel, 24, 8); +MC_HV(qpel, 32, 8); +MC_HV(qpel, 48, 8); +MC_HV(qpel, 64, 8); -MC_HV(epel, hv, 4, 4, hv); -MC_HV(epel, hv, 6, 4, hv); -MC_HV(epel, hv, 8, 4, hv); -MC_HV(epel, hv, 12, 4, hv); -MC_HV(epel, hv, 16, 4, hv); -MC_HV(epel, hv, 24, 4, hv); -MC_HV(epel, hv, 32, 4, hv); +MC_HV(epel, 4, 4); +MC_HV(epel, 6, 4); +MC_HV(epel, 8, 4); +MC_HV(epel, 12, 4); +MC_HV(epel, 16, 4); +MC_HV(epel, 24, 4); +MC_HV(epel, 32, 4); #undef MC_HV diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 5b2409755..e005dd0cd 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -1867,7 +1867,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) // read 0th IFD and store the metadata // (return values > 0 indicate the presence of subimage metadata) - ret = avpriv_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata); + ret = ff_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "mjpeg: error decoding EXIF data\n"); } @@ -2428,7 +2428,10 @@ the_end: avctx->pix_fmt == AV_PIX_FMT_GBRP || avctx->pix_fmt == AV_PIX_FMT_GBRAP ); - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + if (ret) + return ret; + av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); for (p = 0; pnb_components; p++) { uint8_t *line = s->picture_ptr->data[p]; @@ -2487,7 +2490,10 @@ the_end: avctx->pix_fmt == AV_PIX_FMT_GBRP || avctx->pix_fmt == AV_PIX_FMT_GBRAP ); - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + if (ret) + return ret; + av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); for (p = 0; p < s->nb_components; p++) { uint8_t *dst; @@ -2515,7 +2521,10 @@ the_end: } if (s->flipped && !s->rgb) { int j; - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + if (ret) + return ret; + av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); for (index=0; indexnb_components; index++) { uint8_t *dst = s->picture_ptr->data[index]; diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h index c84a40aa6..c36fba5f2 100644 --- a/libavcodec/mjpegdec.h +++ b/libavcodec/mjpegdec.h @@ -39,6 +39,8 @@ #include "hpeldsp.h" #include "idctdsp.h" +#undef near /* This file uses struct member 'near' which in windows.h is defined as empty. */ + #define MAX_COMPONENTS 4 typedef struct MJpegDecodeContext { diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index e6cdaf637..d2fcb8e19 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -358,12 +358,6 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift, &chroma_v_shift); -#if FF_API_EMU_EDGE - //CODEC_FLAG_EMU_EDGE have to be cleared - if(s->avctx->flags & CODEC_FLAG_EMU_EDGE) - return AVERROR(EINVAL); -#endif - if ((avctx->height & 15) && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { av_log(avctx, AV_LOG_ERROR, "Heights which are not a multiple of 16 might fail with some decoders, " diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index 23601c863..3c0330f77 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -119,7 +119,7 @@ uint64_t ff_truehd_layout(int chanmap) return layout; } -static int ff_mlp_get_major_sync_size(const uint8_t * buf, int bufsize) +static int mlp_get_major_sync_size(const uint8_t * buf, int bufsize) { int has_extension, extensions = 0; int size = 28; @@ -149,7 +149,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) av_assert1(get_bits_count(gb) == 0); - header_size = ff_mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); + header_size = mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); if (header_size < 0 || gb->size_in_bits < header_size << 3) { av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); return -1; @@ -357,28 +357,11 @@ static int mlp_parse(AVCodecParserContext *s, if(!avctx->channels || !avctx->channel_layout) { if (mh.stream_type == 0xbb) { /* MLP stream */ - if (avctx->request_channel_layout && - (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) == - avctx->request_channel_layout && - mh.num_substreams > 1) { - avctx->channels = 2; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else { - avctx->channels = mh.channels_mlp; - avctx->channel_layout = mh.channel_layout_mlp; - } + avctx->channels = mh.channels_mlp; + avctx->channel_layout = mh.channel_layout_mlp; } else { /* mh.stream_type == 0xba */ /* TrueHD stream */ - if (avctx->request_channel_layout && - (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) == - avctx->request_channel_layout && - mh.num_substreams > 1) { - avctx->channels = 2; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else if (!mh.channels_thd_stream2 || - (avctx->request_channel_layout && - (avctx->request_channel_layout & mh.channel_layout_thd_stream1) == - avctx->request_channel_layout)) { + if (!mh.channels_thd_stream2) { avctx->channels = mh.channels_thd_stream1; avctx->channel_layout = mh.channel_layout_thd_stream1; } else { diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index d5585d308..63ec3e64b 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -66,7 +66,7 @@ typedef struct SubStream { /// For each channel output by the matrix, the output channel to map it to uint8_t ch_assign[MAX_CHANNELS]; /// The channel layout for this substream - uint64_t ch_layout; + uint64_t mask; /// The matrix encoding mode for this substream enum AVMatrixEncoding matrix_encoding; @@ -180,6 +180,11 @@ static const uint64_t thd_channel_order[] = { AV_CH_LOW_FREQUENCY_2, // LFE2 }; +static int mlp_channel_layout_subset(uint64_t channel_layout, uint64_t mask) +{ + return channel_layout && ((channel_layout & mask) == channel_layout); +} + static uint64_t thd_channel_layout_extract_channel(uint64_t channel_layout, int index) { @@ -390,8 +395,8 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) return AVERROR_PATCHWELCOME; } if ((substr = (mh.num_substreams > 1))) - m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO; - m->substream[substr].ch_layout = mh.channel_layout_mlp; + m->substream[0].mask = AV_CH_LAYOUT_STEREO; + m->substream[substr].mask = mh.channel_layout_mlp; } else { if (mh.stream_type != 0xba) { avpriv_request_sample(m->avctx, @@ -400,15 +405,15 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) return AVERROR_PATCHWELCOME; } if ((substr = (mh.num_substreams > 1))) - m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO; + m->substream[0].mask = AV_CH_LAYOUT_STEREO; if (mh.num_substreams > 2) if (mh.channel_layout_thd_stream2) - m->substream[2].ch_layout = mh.channel_layout_thd_stream2; + m->substream[2].mask = mh.channel_layout_thd_stream2; else - m->substream[2].ch_layout = mh.channel_layout_thd_stream1; - m->substream[substr].ch_layout = mh.channel_layout_thd_stream1; + m->substream[2].mask = mh.channel_layout_thd_stream1; + m->substream[substr].mask = mh.channel_layout_thd_stream1; - if (m->avctx->channels<=2 && m->substream[substr].ch_layout == AV_CH_LAYOUT_MONO && m->max_decoded_substream == 1) { + if (m->avctx->channels<=2 && m->substream[substr].mask == AV_CH_LAYOUT_MONO && m->max_decoded_substream == 1) { av_log(m->avctx, AV_LOG_DEBUG, "Mono stream with 2 substreams, ignoring 2nd\n"); m->max_decoded_substream = 0; if (m->avctx->channels==2) @@ -533,12 +538,12 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, s->max_channel = max_channel; s->max_matrix_channel = max_matrix_channel; - if (m->avctx->request_channel_layout && (s->ch_layout & m->avctx->request_channel_layout) == - m->avctx->request_channel_layout && m->max_decoded_substream > substr) { + if (mlp_channel_layout_subset(m->avctx->request_channel_layout, s->mask) && + m->max_decoded_substream > substr) { av_log(m->avctx, AV_LOG_DEBUG, "Extracting %d-channel downmix (0x%"PRIx64") from substream %d. " "Further substreams will be skipped.\n", - s->max_channel + 1, s->ch_layout, substr); + s->max_channel + 1, s->mask, substr); m->max_decoded_substream = substr; } @@ -565,9 +570,9 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, for (ch = 0; ch <= s->max_matrix_channel; ch++) { int ch_assign = get_bits(gbp, 6); if (m->avctx->codec_id == AV_CODEC_ID_TRUEHD) { - uint64_t channel = thd_channel_layout_extract_channel(s->ch_layout, + uint64_t channel = thd_channel_layout_extract_channel(s->mask, ch_assign); - ch_assign = av_get_channel_layout_channel_index(s->ch_layout, + ch_assign = av_get_channel_layout_channel_index(s->mask, channel); } if (ch_assign < 0 || ch_assign > s->max_matrix_channel) { @@ -609,7 +614,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, if (substr == m->max_decoded_substream) { m->avctx->channels = s->max_matrix_channel + 1; - m->avctx->channel_layout = s->ch_layout; + m->avctx->channel_layout = s->mask; m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(s->ch_assign, s->output_shift, s->max_matrix_channel, diff --git a/libavcodec/mlpdsp.c b/libavcodec/mlpdsp.c index fbafa92d7..32a4503b6 100644 --- a/libavcodec/mlpdsp.c +++ b/libavcodec/mlpdsp.c @@ -117,7 +117,7 @@ int32_t ff_mlp_pack_output(int32_t lossless_check_data, (1U << output_shift[mat_ch]); lossless_check_data ^= (sample & 0xffffff) << mat_ch; if (is32) - *data_32++ = sample << 8; + *data_32++ = sample * 256U; else *data_16++ = sample >> 8; } diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index 0b1195dc3..647a22ef7 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -34,6 +34,7 @@ #include #include "avcodec.h" +#include "hwaccel.h" #include "internal.h" #include "libavutil/avassert.h" #include "libavutil/buffer.h" @@ -807,32 +808,9 @@ static int ffmmal_decode(AVCodecContext *avctx, void *data, int *got_frame, return ret; } -AVHWAccel ff_h264_mmal_hwaccel = { - .name = "h264_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_MMAL, -}; - -AVHWAccel ff_mpeg2_mmal_hwaccel = { - .name = "mpeg2_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .pix_fmt = AV_PIX_FMT_MMAL, -}; - -AVHWAccel ff_mpeg4_mmal_hwaccel = { - .name = "mpeg4_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .pix_fmt = AV_PIX_FMT_MMAL, -}; - -AVHWAccel ff_vc1_mmal_hwaccel = { - .name = "vc1_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VC1, - .pix_fmt = AV_PIX_FMT_MMAL, +static const AVCodecHWConfigInternal *mmal_hw_configs[] = { + HW_CONFIG_INTERNAL(MMAL), + NULL }; static const AVOption options[]={ @@ -844,6 +822,7 @@ static const AVOption options[]={ #define FFMMAL_DEC_CLASS(NAME) \ static const AVClass ffmmal_##NAME##_dec_class = { \ .class_name = "mmal_" #NAME "_dec", \ + .item_name = av_default_item_name, \ .option = options, \ .version = LIBAVUTIL_VERSION_INT, \ }; @@ -861,11 +840,13 @@ static const AVOption options[]={ .decode = ffmmal_decode, \ .flush = ffmmal_flush, \ .priv_class = &ffmmal_##NAME##_dec_class, \ - .capabilities = AV_CODEC_CAP_DELAY, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \ .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, \ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MMAL, \ AV_PIX_FMT_YUV420P, \ AV_PIX_FMT_NONE}, \ + .hw_configs = mmal_hw_configs, \ + .wrapper_name = "mmal", \ }; FFMMAL_DEC(h264, AV_CODEC_ID_H264) diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 316d16a77..8b5ce2117 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -313,26 +313,6 @@ int ff_init_me(MpegEncContext *s){ return -1; } -#if FF_API_MOTION_EST - //special case of snow is needed because snow uses its own iterative ME code -FF_DISABLE_DEPRECATION_WARNINGS - if (s->motion_est == FF_ME_EPZS) { - if (s->me_method == ME_ZERO) - s->motion_est = FF_ME_ZERO; - else if (s->me_method == ME_EPZS) - s->motion_est = FF_ME_EPZS; - else if (s->me_method == ME_X1) - s->motion_est = FF_ME_XONE; - else if (s->avctx->codec_id != AV_CODEC_ID_SNOW) { - av_log(s->avctx, AV_LOG_ERROR, - "me_method is only allowed to be set to zero and epzs; " - "for hex,umh,full and others see dia_size\n"); - return -1; - } - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - c->avctx= s->avctx; if(s->codec_id == AV_CODEC_ID_H261) diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c index fb5085c3e..bd1957772 100644 --- a/libavcodec/movtextdec.c +++ b/libavcodec/movtextdec.c @@ -436,6 +436,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx, int text_length, tsmb_type, ret_tsmb; uint64_t tsmb_size; const uint8_t *tsmb; + size_t i; if (!ptr || avpkt->size < 2) return AVERROR_INVALIDDATA; @@ -495,7 +496,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx, if (tsmb_size > avpkt->size - m->tracksize) break; - for (size_t i = 0; i < box_count; i++) { + for (i = 0; i < box_count; i++) { if (tsmb_type == box_types[i].type) { if (m->tracksize + m->size_var + box_types[i].base_size > avpkt->size) break; diff --git a/libavcodec/mpeg12.h b/libavcodec/mpeg12.h index f551504b8..1ec99f17e 100644 --- a/libavcodec/mpeg12.h +++ b/libavcodec/mpeg12.h @@ -73,4 +73,8 @@ void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], 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/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 4e68be27f..ac5ac4bca 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -36,6 +36,7 @@ #include "avcodec.h" #include "bytestream.h" #include "error_resilience.h" +#include "hwaccel.h" #include "idctdsp.h" #include "internal.h" #include "mpeg_er.h" @@ -47,7 +48,6 @@ #include "profiles.h" #include "thread.h" #include "version.h" -#include "vdpau_compat.h" #include "xvmc_internal.h" typedef struct Mpeg1Context { @@ -1131,12 +1131,12 @@ static void quant_matrix_rebuild(uint16_t *matrix, const uint8_t *old_perm, } static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = { +#if CONFIG_MPEG1_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_MPEG1_XVMC_HWACCEL AV_PIX_FMT_XVMC, #endif -#if CONFIG_MPEG1_VDPAU_DECODER && FF_API_VDPAU - AV_PIX_FMT_VDPAU_MPEG1, -#endif #if CONFIG_MPEG1_VDPAU_HWACCEL AV_PIX_FMT_VDPAU, #endif @@ -1145,12 +1145,12 @@ static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = { }; static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { +#if CONFIG_MPEG2_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_MPEG2_XVMC_HWACCEL AV_PIX_FMT_XVMC, #endif -#if CONFIG_MPEG_VDPAU_DECODER && FF_API_VDPAU - AV_PIX_FMT_VDPAU_MPEG2, -#endif #if CONFIG_MPEG2_VDPAU_HWACCEL AV_PIX_FMT_VDPAU, #endif @@ -1181,12 +1181,6 @@ static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = { AV_PIX_FMT_NONE }; -#if FF_API_VDPAU -static inline int uses_vdpau(AVCodecContext *avctx) { - return avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG1 || avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG2; -} -#endif - static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; @@ -1211,11 +1205,7 @@ static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx) { // until then pix_fmt may be changed right after codec init - if (avctx->hwaccel -#if FF_API_VDPAU - || uses_vdpau(avctx) -#endif - ) + if (avctx->hwaccel) if (avctx->idct_algo == FF_IDCT_AUTO) avctx->idct_algo = FF_IDCT_NONE; @@ -1224,11 +1214,6 @@ static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx) MpegEncContext *s = &s1->mpeg_enc_ctx; s->pack_pblocks = 1; -#if FF_API_XVMC -FF_DISABLE_DEPRECATION_WARNINGS - avctx->xvmc_acceleration = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_XVMC */ } } @@ -2257,8 +2242,52 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, av_freep(&s1->a53_caption); s1->a53_caption_size = cc_count * 3; s1->a53_caption = av_malloc(s1->a53_caption_size); - if (s1->a53_caption) + if (!s1->a53_caption) { + s1->a53_caption_size = 0; + } else { memcpy(s1->a53_caption, p + 7, s1->a53_caption_size); + } + avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; + } + return 1; + } else if (buf_size >= 2 && + p[0] == 0x03 && (p[1]&0x7f) == 0x01) { + /* extract SCTE-20 CC data */ + GetBitContext gb; + int cc_count = 0; + int i; + + init_get_bits(&gb, p + 2, buf_size - 2); + cc_count = get_bits(&gb, 5); + if (cc_count > 0) { + av_freep(&s1->a53_caption); + s1->a53_caption_size = cc_count * 3; + s1->a53_caption = av_mallocz(s1->a53_caption_size); + if (!s1->a53_caption) { + s1->a53_caption_size = 0; + } else { + uint8_t field, cc1, cc2; + uint8_t *cap = s1->a53_caption; + for (i = 0; i < cc_count && get_bits_left(&gb) >= 26; i++) { + skip_bits(&gb, 2); // priority + field = get_bits(&gb, 2); + skip_bits(&gb, 5); // line_offset + cc1 = get_bits(&gb, 8); + cc2 = get_bits(&gb, 8); + skip_bits(&gb, 1); // marker + + if (!field) { // forbidden + cap[0] = cap[1] = cap[2] = 0x00; + } else { + field = (field == 2 ? 1 : 0); + if (!s1->mpeg_enc_ctx.top_field_first) field = !field; + cap[0] = 0x04 | field; + cap[1] = ff_reverse[cc1]; + cap[2] = ff_reverse[cc2]; + } + cap += 3; + } + } avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; } return 1; @@ -2300,7 +2329,9 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, av_freep(&s1->a53_caption); s1->a53_caption_size = cc_count * 6; s1->a53_caption = av_malloc(s1->a53_caption_size); - if (s1->a53_caption) { + if (!s1->a53_caption) { + s1->a53_caption_size = 0; + } else { uint8_t field1 = !!(p[4] & 0x80); uint8_t *cap = s1->a53_caption; p += 5; @@ -2356,11 +2387,6 @@ static void mpeg_decode_user_data(AVCodecContext *avctx, if (flags & 0x40) { if (buf_end - p < 1) return; -#if FF_API_AFD -FF_DISABLE_DEPRECATION_WARNINGS - avctx->dtg_active_format = p[0] & 0x0f; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_AFD */ s1->has_afd = 1; s1->afd = p[0] & 0x0f; } @@ -2460,12 +2486,6 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, s2->er.error_count += s2->thread_context[i]->er.error_count; } -#if FF_API_VDPAU - if ((CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER) - && uses_vdpau(avctx)) - ff_vdpau_mpeg_picture_complete(s2, buf, buf_size, s->slice_count); -#endif - ret = slice_end(avctx, picture); if (ret < 0) return ret; @@ -2717,13 +2737,6 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } -#if FF_API_VDPAU - if (uses_vdpau(avctx)) { - s->slice_count++; - break; - } -#endif - if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) && !avctx->hwaccel) { @@ -2878,7 +2891,22 @@ AVCodec ff_mpeg1video_decoder = { .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = flush, .max_lowres = 3, - .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context) + .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MPEG2_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg1), +#endif +#if CONFIG_MPEG1_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg1), +#endif +#if CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg1), +#endif +#if CONFIG_MPEG1_XVMC_HWACCEL + HWACCEL_XVMC(mpeg1), +#endif + NULL + }, }; AVCodec ff_mpeg2video_decoder = { @@ -2897,6 +2925,33 @@ AVCodec ff_mpeg2video_decoder = { .flush = flush, .max_lowres = 3, .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MPEG2_DXVA2_HWACCEL + HWACCEL_DXVA2(mpeg2), +#endif +#if CONFIG_MPEG2_D3D11VA_HWACCEL + HWACCEL_D3D11VA(mpeg2), +#endif +#if CONFIG_MPEG2_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(mpeg2), +#endif +#if CONFIG_MPEG2_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg2), +#endif +#if CONFIG_MPEG2_VAAPI_HWACCEL + HWACCEL_VAAPI(mpeg2), +#endif +#if CONFIG_MPEG2_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg2), +#endif +#if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg2), +#endif +#if CONFIG_MPEG2_XVMC_HWACCEL + HWACCEL_XVMC(mpeg2), +#endif + NULL + }, }; //legacy decoder @@ -2914,73 +2969,3 @@ AVCodec ff_mpegvideo_decoder = { .flush = flush, .max_lowres = 3, }; - -#if FF_API_XVMC -#if CONFIG_MPEG_XVMC_DECODER -FF_DISABLE_DEPRECATION_WARNINGS -static av_cold int mpeg_mc_decode_init(AVCodecContext *avctx) -{ - if (avctx->active_thread_type & FF_THREAD_SLICE) - return -1; - if (!(avctx->slice_flags & SLICE_FLAG_CODED_ORDER)) - return -1; - if (!(avctx->slice_flags & SLICE_FLAG_ALLOW_FIELD)) { - ff_dlog(avctx, "mpeg12.c: XvMC decoder will work better if SLICE_FLAG_ALLOW_FIELD is set\n"); - } - mpeg_decode_init(avctx); - - avctx->pix_fmt = AV_PIX_FMT_XVMC_MPEG2_IDCT; - avctx->xvmc_acceleration = 2; // 2 - the blocks are packed! - - return 0; -} - -AVCodec ff_mpeg_xvmc_decoder = { - .name = "mpegvideo_xvmc", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video XvMC (X-Video Motion Compensation)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO_XVMC, - .priv_data_size = sizeof(Mpeg1Context), - .init = mpeg_mc_decode_init, - .close = mpeg_decode_end, - .decode = mpeg_decode_frame, - .capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | - AV_CODEC_CAP_TRUNCATED | CODEC_CAP_HWACCEL | - AV_CODEC_CAP_DELAY, - .flush = flush, -}; -FF_ENABLE_DEPRECATION_WARNINGS -#endif -#endif /* FF_API_XVMC */ - -#if CONFIG_MPEG_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_mpeg_vdpau_decoder = { - .name = "mpegvideo_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video (VDPAU acceleration)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .priv_data_size = sizeof(Mpeg1Context), - .init = mpeg_decode_init, - .close = mpeg_decode_end, - .decode = mpeg_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | - AV_CODEC_CAP_HWACCEL_VDPAU | AV_CODEC_CAP_DELAY, - .flush = flush, -}; -#endif - -#if CONFIG_MPEG1_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_mpeg1_vdpau_decoder = { - .name = "mpeg1video_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video (VDPAU acceleration)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG1VIDEO, - .priv_data_size = sizeof(Mpeg1Context), - .init = mpeg_decode_init, - .close = mpeg_decode_end, - .decode = mpeg_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | - AV_CODEC_CAP_HWACCEL_VDPAU | AV_CODEC_CAP_DELAY, - .flush = flush, -}; -#endif diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index f45598a08..0084f544f 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -353,7 +353,7 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) if (s->seq_disp_ext == 1 || (s->seq_disp_ext == -1 && use_seq_disp_ext)) { put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 2); // sequence display extension - put_bits(&s->pb, 3, 0); // video_format: 0 is components + put_bits(&s->pb, 3, 5); // video_format: 5 is unspecified put_bits(&s->pb, 1, 1); // colour_description put_bits(&s->pb, 8, s->avctx->color_primaries); // colour_primaries put_bits(&s->pb, 8, s->avctx->color_trc); // transfer_characteristics diff --git a/libavcodec/mpeg12framerate.c b/libavcodec/mpeg12framerate.c index 094cd180a..ab3d35117 100644 --- a/libavcodec/mpeg12framerate.c +++ b/libavcodec/mpeg12framerate.c @@ -18,6 +18,9 @@ #include "libavutil/rational.h" +#include "mpeg12.h" +#include "mpeg12data.h" + const AVRational ff_mpeg12_frame_rate_tab[16] = { { 0, 0}, {24000, 1001}, @@ -37,3 +40,64 @@ const AVRational ff_mpeg12_frame_rate_tab[16] = { { 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/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c new file mode 100644 index 000000000..b9a49ab94 --- /dev/null +++ b/libavcodec/mpeg2_metadata_bsf.c @@ -0,0 +1,312 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/avstring.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_mpeg2.h" +#include "mpeg12.h" + +typedef struct MPEG2MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment fragment; + + MPEG2RawExtensionData sequence_display_extension; + + AVRational display_aspect_ratio; + + AVRational frame_rate; + + int video_format; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int mpeg1_warned; +} MPEG2MetadataContext; + + +static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, + CodedBitstreamFragment *frag) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + MPEG2RawSequenceHeader *sh = NULL; + MPEG2RawSequenceExtension *se = NULL; + MPEG2RawSequenceDisplayExtension *sde = NULL; + int i, se_pos, add_sde = 0; + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == MPEG2_START_SEQUENCE_HEADER) { + sh = frag->units[i].content; + } else if (frag->units[i].type == MPEG2_START_EXTENSION) { + MPEG2RawExtensionData *ext = frag->units[i].content; + if (ext->extension_start_code_identifier == + MPEG2_EXTENSION_SEQUENCE) { + se = &ext->data.sequence; + se_pos = i; + } else if (ext->extension_start_code_identifier == + MPEG2_EXTENSION_SEQUENCE_DISPLAY) { + sde = &ext->data.sequence_display; + } + } + } + + if (!sh || !se) { + // No sequence header and sequence extension: not an MPEG-2 video + // sequence. + if (sh && !ctx->mpeg1_warned) { + av_log(bsf, AV_LOG_WARNING, "Stream contains a sequence " + "header but not a sequence extension: maybe it's " + "actually MPEG-1?\n"); + ctx->mpeg1_warned = 1; + } + return 0; + } + + if (ctx->display_aspect_ratio.num && ctx->display_aspect_ratio.den) { + int num, den; + + av_reduce(&num, &den, ctx->display_aspect_ratio.num, + ctx->display_aspect_ratio.den, 65535); + + if (num == 4 && den == 3) + sh->aspect_ratio_information = 2; + else if (num == 16 && den == 9) + sh->aspect_ratio_information = 3; + else if (num == 221 && den == 100) + sh->aspect_ratio_information = 4; + else + sh->aspect_ratio_information = 1; + } + + if (ctx->frame_rate.num && ctx->frame_rate.den) { + int code, ext_n, ext_d; + + ff_mpeg12_find_best_frame_rate(ctx->frame_rate, + &code, &ext_n, &ext_d, 0); + + sh->frame_rate_code = code; + se->frame_rate_extension_n = ext_n; + se->frame_rate_extension_d = ext_d; + } + + if (ctx->video_format >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + if (!sde) { + add_sde = 1; + ctx->sequence_display_extension.extension_start_code = + MPEG2_START_EXTENSION; + ctx->sequence_display_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE_DISPLAY; + sde = &ctx->sequence_display_extension.data.sequence_display; + + *sde = (MPEG2RawSequenceDisplayExtension) { + .video_format = 5, + + .colour_description = 0, + .colour_primaries = 2, + .transfer_characteristics = 2, + .matrix_coefficients = 2, + + .display_horizontal_size = + se->horizontal_size_extension << 12 | sh->horizontal_size_value, + .display_vertical_size = + se->vertical_size_extension << 12 | sh->vertical_size_value, + }; + } + + if (ctx->video_format >= 0) + sde->video_format = ctx->video_format; + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + sde->colour_description = 1; + + if (ctx->colour_primaries >= 0) + sde->colour_primaries = ctx->colour_primaries; + else if (add_sde) + sde->colour_primaries = 2; + + if (ctx->transfer_characteristics >= 0) + sde->transfer_characteristics = ctx->transfer_characteristics; + else if (add_sde) + sde->transfer_characteristics = 2; + + if (ctx->matrix_coefficients >= 0) + sde->matrix_coefficients = ctx->matrix_coefficients; + else if (add_sde) + sde->matrix_coefficients = 2; + } + } + + if (add_sde) { + int err; + + err = ff_cbs_insert_unit_content(ctx->cbc, frag, se_pos + 1, + MPEG2_START_EXTENSION, + &ctx->sequence_display_extension); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert new sequence " + "display extension.\n"); + return err; + } + } + + return 0; +} + +static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *frag = &ctx->fragment; + int err; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + goto fail; + + err = ff_cbs_read_packet(ctx->cbc, frag, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + err = mpeg2_metadata_update_fragment(bsf, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to update frame fragment.\n"); + goto fail; + } + + err = ff_cbs_write_packet(ctx->cbc, out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) { + av_packet_unref(out); + goto fail; + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, frag); + + av_packet_free(&in); + + return err; +} + +static int mpeg2_metadata_init(AVBSFContext *bsf) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->fragment; + int err; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_MPEG2VIDEO, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + err = mpeg2_metadata_update_fragment(bsf, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to update metadata fragment.\n"); + goto fail; + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, frag); + return err; +} + +static void mpeg2_metadata_close(AVBSFContext *bsf) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(MPEG2MetadataContext, x) +static const AVOption mpeg2_metadata_options[] = { + { "display_aspect_ratio", "Set display aspect ratio (table 6-3)", + OFFSET(display_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, 65535 }, + + { "frame_rate", "Set frame rate", + OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX }, + + { "video_format", "Set video format (table 6-6)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7 }, + { "colour_primaries", "Set colour primaries (table 6-7)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "transfer_characteristics", "Set transfer characteristics (table 6-8)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "matrix_coefficients", "Set matrix coefficients (table 6-9)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + + { NULL } +}; + +static const AVClass mpeg2_metadata_class = { + .class_name = "mpeg2_metadata_bsf", + .item_name = av_default_item_name, + .option = mpeg2_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID mpeg2_metadata_codec_ids[] = { + AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mpeg2_metadata_bsf = { + .name = "mpeg2_metadata", + .priv_data_size = sizeof(MPEG2MetadataContext), + .priv_class = &mpeg2_metadata_class, + .init = &mpeg2_metadata_init, + .close = &mpeg2_metadata_close, + .filter = &mpeg2_metadata_filter, + .codec_ids = mpeg2_metadata_codec_ids, +}; diff --git a/libavcodec/mpeg4audio.c b/libavcodec/mpeg4audio.c index b6bb32344..219714752 100644 --- a/libavcodec/mpeg4audio.c +++ b/libavcodec/mpeg4audio.c @@ -167,43 +167,3 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, return ff_mpeg4audio_get_config_gb(c, &gb, sync_extension); } - -static av_always_inline unsigned int copy_bits(PutBitContext *pb, - GetBitContext *gb, - int bits) -{ - unsigned int el = get_bits(gb, bits); - put_bits(pb, bits, el); - return el; -} - -int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb) -{ - int five_bit_ch, four_bit_ch, comment_size, bits; - int offset = put_bits_count(pb); - - copy_bits(pb, gb, 10); //Tag, Object Type, Frequency - five_bit_ch = copy_bits(pb, gb, 4); //Front - five_bit_ch += copy_bits(pb, gb, 4); //Side - five_bit_ch += copy_bits(pb, gb, 4); //Back - four_bit_ch = copy_bits(pb, gb, 2); //LFE - four_bit_ch += copy_bits(pb, gb, 3); //Data - five_bit_ch += copy_bits(pb, gb, 4); //Coupling - if (copy_bits(pb, gb, 1)) //Mono Mixdown - copy_bits(pb, gb, 4); - if (copy_bits(pb, gb, 1)) //Stereo Mixdown - copy_bits(pb, gb, 4); - if (copy_bits(pb, gb, 1)) //Matrix Mixdown - copy_bits(pb, gb, 3); - for (bits = five_bit_ch*5+four_bit_ch*4; bits > 16; bits -= 16) - copy_bits(pb, gb, 16); - if (bits) - copy_bits(pb, gb, bits); - avpriv_align_put_bits(pb); - align_get_bits(gb); - comment_size = copy_bits(pb, gb, 8); - for (; comment_size > 0; comment_size--) - copy_bits(pb, gb, 8); - - return put_bits_count(pb) - offset; -} diff --git a/libavcodec/mpeg4audio.h b/libavcodec/mpeg4audio.h index 8fd32f96b..b9cea8af1 100644 --- a/libavcodec/mpeg4audio.h +++ b/libavcodec/mpeg4audio.h @@ -23,7 +23,11 @@ #define AVCODEC_MPEG4AUDIO_H #include + +#include "libavutil/attributes.h" + #include "get_bits.h" +#include "internal.h" #include "put_bits.h" typedef struct MPEG4AudioConfig { @@ -41,7 +45,7 @@ typedef struct MPEG4AudioConfig { int frame_length_short; } MPEG4AudioConfig; -extern av_export const int avpriv_mpeg4audio_sample_rates[16]; +extern av_export_avcodec const int avpriv_mpeg4audio_sample_rates[16]; extern const uint8_t ff_mpeg4audio_channels[8]; /** @@ -115,6 +119,44 @@ enum AudioObjectType { #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/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h index 515b008ae..0ba502d50 100644 --- a/libavcodec/mpeg4video.h +++ b/libavcodec/mpeg4video.h @@ -43,6 +43,9 @@ #define ACE_VO_TYPE 12 #define ADV_SIMPLE_VO_TYPE 17 +#define VOT_VIDEO_ID 1 +#define VOT_STILL_TEXTURE_ID 2 + // aspect_ratio_info #define EXTENDED_PAR 15 diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index cd39131d5..12755b5e8 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -25,6 +25,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "error_resilience.h" +#include "hwaccel.h" #include "idctdsp.h" #include "internal.h" #include "mpegutils.h" @@ -189,6 +190,10 @@ static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *g if (w <= 0 || h <= 0) return AVERROR_INVALIDDATA; + /* the decoder was not properly initialized and we cannot continue */ + if (sprite_trajectory.table == NULL) + return AVERROR_INVALIDDATA; + for (i = 0; i < ctx->num_sprite_warping_points; i++) { int length; int x = 0, y = 0; @@ -1749,6 +1754,38 @@ static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb) return 0; } +static int mpeg4_decode_visual_object(MpegEncContext *s, GetBitContext *gb) +{ + int visual_object_type; + int is_visual_object_identifier = get_bits1(gb); + + if (is_visual_object_identifier) { + skip_bits(gb, 4+3); + } + visual_object_type = get_bits(gb, 4); + + if (visual_object_type == VOT_VIDEO_ID || + visual_object_type == VOT_STILL_TEXTURE_ID) { + int video_signal_type = get_bits1(gb); + if (video_signal_type) { + int video_range, color_description; + skip_bits(gb, 3); // video_format + video_range = get_bits1(gb); + color_description = get_bits1(gb); + + s->avctx->color_range = video_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + if (color_description) { + s->avctx->color_primaries = get_bits(gb, 8); + s->avctx->color_trc = get_bits(gb, 8); + s->avctx->colorspace = get_bits(gb, 8); + } + } + } + + return 0; +} + static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) { MpegEncContext *s = &ctx->m; @@ -2149,8 +2186,15 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) e = sscanf(buf, "FFmpeg v%d.%d.%d / libavcodec build: %d", &ver, &ver2, &ver3, &build); if (e != 4) { e = sscanf(buf, "Lavc%d.%d.%d", &ver, &ver2, &ver3) + 1; - if (e > 1) - build = (ver << 16) + (ver2 << 8) + ver3; + if (e > 1) { + if (ver > 0xFFU || ver2 > 0xFFU || ver3 > 0xFFU) { + av_log(s->avctx, AV_LOG_WARNING, + "Unknown Lavc version string encountered, %d.%d.%d; " + "clamping sub-version values to 8-bits.\n", + ver, ver2, ver3); + } + build = ((ver & 0xFF) << 16) + ((ver2 & 0xFF) << 8) + (ver3 & 0xFF); + } } if (e != 4) { if (strcmp(buf, "ffmpeg") == 0) @@ -2672,6 +2716,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) mpeg4_decode_gop_header(s, gb); } else if (startcode == VOS_STARTCODE) { mpeg4_decode_profile_level(s, gb); + } else if (startcode == VISUAL_OBJ_STARTCODE) { + mpeg4_decode_visual_object(s, gb); } else if (startcode == VOP_STARTCODE) { break; } @@ -2819,10 +2865,10 @@ static const AVOption mpeg4_options[] = { }; static const AVClass mpeg4_class = { - "MPEG4 Video Decoder", - av_default_item_name, - mpeg4_options, - LIBAVUTIL_VERSION_INT, + .class_name = "MPEG4 Video Decoder", + .item_name = av_default_item_name, + .option = mpeg4_options, + .version = LIBAVUTIL_VERSION_INT, }; AVCodec ff_mpeg4_decoder = { @@ -2844,30 +2890,19 @@ AVCodec ff_mpeg4_decoder = { .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg4_update_thread_context), .priv_class = &mpeg4_class, -}; - - -#if CONFIG_MPEG4_VDPAU_DECODER && FF_API_VDPAU -static const AVClass mpeg4_vdpau_class = { - "MPEG4 Video VDPAU Decoder", - av_default_item_name, - mpeg4_options, - LIBAVUTIL_VERSION_INT, -}; - -AVCodec ff_mpeg4_vdpau_decoder = { - .name = "mpeg4_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 (VDPAU)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .priv_data_size = sizeof(Mpeg4DecContext), - .init = decode_init, - .close = ff_h263_decode_end, - .decode = ff_h263_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | AV_CODEC_CAP_DELAY | - AV_CODEC_CAP_HWACCEL_VDPAU, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VDPAU_MPEG4, - AV_PIX_FMT_NONE }, - .priv_class = &mpeg4_vdpau_class, -}; + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MPEG4_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg4), #endif +#if CONFIG_MPEG4_VAAPI_HWACCEL + HWACCEL_VAAPI(mpeg4), +#endif +#if CONFIG_MPEG4_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg4), +#endif +#if CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg4), +#endif + NULL + }, +}; diff --git a/libavcodec/mpegaudiodata.h b/libavcodec/mpegaudiodata.h index 29a26588b..a188150cb 100644 --- a/libavcodec/mpegaudiodata.h +++ b/libavcodec/mpegaudiodata.h @@ -29,13 +29,13 @@ #include -#include "libavutil/internal.h" +#include "internal.h" #define MODE_EXT_MS_STEREO 2 #define MODE_EXT_I_STEREO 1 -extern av_export const uint16_t avpriv_mpa_bitrate_tab[2][3][15]; -extern av_export const uint16_t avpriv_mpa_freq_tab[3]; +extern av_export_avcodec const uint16_t avpriv_mpa_bitrate_tab[2][3][15]; +extern av_export_avcodec const uint16_t avpriv_mpa_freq_tab[3]; extern const int ff_mpa_sblimit_table[5]; extern const int ff_mpa_quant_steps[17]; extern const int ff_mpa_quant_bits[17]; diff --git a/libavcodec/mpegaudiodecheader.c b/libavcodec/mpegaudiodecheader.c index ae86b087f..6cc79f18b 100644 --- a/libavcodec/mpegaudiodecheader.c +++ b/libavcodec/mpegaudiodecheader.c @@ -152,15 +152,3 @@ int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *fr *bit_rate = s->bit_rate; return s->frame_size; } - -#if LIBAVCODEC_VERSION_MAJOR < 58 -int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate, enum AVCodecID *codec_id) -{ - return ff_mpa_decode_header(head, sample_rate, channels, frame_size, bit_rate, codec_id); -} - -int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate) -{ - return ff_mpa_decode_header(head, sample_rate, channels, frame_size, bit_rate, &avctx->codec_id); -} -#endif diff --git a/libavcodec/mpegaudiodecheader.h b/libavcodec/mpegaudiodecheader.h index 952ba1744..1cb921646 100644 --- a/libavcodec/mpegaudiodecheader.h +++ b/libavcodec/mpegaudiodecheader.h @@ -57,11 +57,6 @@ int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header); int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id); -#if LIBAVCODEC_VERSION_MAJOR < 58 -int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate); -int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id); -#endif - /* fast header check for resync */ static inline int ff_mpa_check_header(uint32_t header){ /* header */ diff --git a/libavcodec/mpegaudiodsp.c b/libavcodec/mpegaudiodsp.c index a5d20df62..3cafca27b 100644 --- a/libavcodec/mpegaudiodsp.c +++ b/libavcodec/mpegaudiodsp.c @@ -20,17 +20,21 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/thread.h" #include "mpegaudiodsp.h" #include "dct.h" #include "dct32.h" +static AVOnce mpadsp_float_table_init = AV_ONCE_INIT; +static AVOnce mpadsp_fixed_table_init = AV_ONCE_INIT; + av_cold void ff_mpadsp_init(MPADSPContext *s) { DCTContext dct; ff_dct_init(&dct, 5, DCT_II); - ff_init_mpadsp_tabs_float(); - ff_init_mpadsp_tabs_fixed(); + ff_thread_once(&mpadsp_float_table_init, &ff_init_mpadsp_tabs_float); + ff_thread_once(&mpadsp_fixed_table_init, &ff_init_mpadsp_tabs_fixed); s->apply_window_float = ff_mpadsp_apply_window_float; s->apply_window_fixed = ff_mpadsp_apply_window_fixed; diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c index 53fb35b4b..2be670cdb 100644 --- a/libavcodec/mpegpicture.c +++ b/libavcodec/mpegpicture.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "motion_est.h" @@ -58,11 +59,7 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, { int alloc_size = FFALIGN(FFABS(linesize) + 64, 32); - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) return 0; if (linesize < 24) { @@ -159,7 +156,8 @@ static int alloc_frame_buffer(AVCodecContext *avctx, Picture *pic, return -1; } - if (pic->f->linesize[1] != pic->f->linesize[2]) { + 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); @@ -377,8 +375,10 @@ int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src) if (src->hwaccel_picture_private) { dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); - if (!dst->hwaccel_priv_buf) + if (!dst->hwaccel_priv_buf) { + ret = AVERROR(ENOMEM); goto fail; + } dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; } diff --git a/libavcodec/mpegutils.c b/libavcodec/mpegutils.c index 62cc36aa6..3f9454061 100644 --- a/libavcodec/mpegutils.c +++ b/libavcodec/mpegutils.c @@ -23,10 +23,31 @@ #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, @@ -78,3 +99,295 @@ void ff_draw_horiz_band(AVCodecContext *avctx, 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/libavcodec/mpegutils.h b/libavcodec/mpegutils.h index 9cfadfc4c..1ed21c19b 100644 --- a/libavcodec/mpegutils.h +++ b/libavcodec/mpegutils.h @@ -48,7 +48,6 @@ #define MAX_FCODE 7 /* MB types */ -#if !FF_API_MB_TYPE #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 @@ -70,7 +69,6 @@ #define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) #define MB_TYPE_QUANT (1 << 16) #define MB_TYPE_CBP (1 << 17) -#endif #define MB_TYPE_INTRA MB_TYPE_INTRA4x4 // default mb_type if there is just one type @@ -139,4 +137,12 @@ 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/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index c4089972f..18c3a87ed 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -876,7 +876,7 @@ static void clear_context(MpegEncContext *s) */ av_cold int ff_mpv_common_init(MpegEncContext *s) { - int i; + int i, ret; int nb_slices = (HAVE_THREADS && s->avctx->active_thread_type & FF_THREAD_SLICE) ? s->avctx->thread_count : 1; @@ -915,10 +915,11 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) dct_init(s); /* set chroma shifts */ - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, - &s->chroma_x_shift, - &s->chroma_y_shift); - + 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); @@ -1311,11 +1312,7 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) return -1; } - if (!avctx->hwaccel -#if FF_API_CAP_VDPAU - && !(avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) -#endif - ) { + 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); @@ -1422,540 +1419,6 @@ void ff_mpv_frame_end(MpegEncContext *s) ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0); } - -#if FF_API_VISMV -static int clip_line(int *sx, int *sy, int *ex, int *ey, int maxx) -{ - if(*sx > *ex) - return clip_line(ex, ey, sx, sy, maxx); - - if (*sx < 0) { - if (*ex < 0) - return 1; - *sy = *ey + (*sy - *ey) * (int64_t)*ex / (*ex - *sx); - *sx = 0; - } - - if (*ex > maxx) { - if (*sx > maxx) - return 1; - *ey = *sy + (*ey - *sy) * (int64_t)(maxx - *sx) / (*ex - *sx); - *ex = maxx; - } - return 0; -} - - -/** - * Draw a line from (ex, ey) -> (sx, sy). - * @param w width of the image - * @param h height of the image - * @param stride stride/linesize of the image - * @param color color of the arrow - */ -static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, - int w, int h, int stride, int color) -{ - int x, y, fr, f; - - if (clip_line(&sx, &sy, &ex, &ey, w - 1)) - return; - if (clip_line(&sy, &sx, &ey, &ex, h - 1)) - return; - - sx = av_clip(sx, 0, w - 1); - sy = av_clip(sy, 0, h - 1); - ex = av_clip(ex, 0, w - 1); - ey = av_clip(ey, 0, h - 1); - - buf[sy * stride + sx] += color; - - if (FFABS(ex - sx) > FFABS(ey - sy)) { - if (sx > ex) { - FFSWAP(int, sx, ex); - FFSWAP(int, sy, ey); - } - buf += sx + sy * stride; - ex -= sx; - f = ((ey - sy) << 16) / ex; - for (x = 0; x <= ex; x++) { - y = (x * f) >> 16; - fr = (x * f) & 0xFFFF; - buf[y * stride + x] += (color * (0x10000 - fr)) >> 16; - if(fr) buf[(y + 1) * stride + x] += (color * fr ) >> 16; - } - } else { - if (sy > ey) { - FFSWAP(int, sx, ex); - FFSWAP(int, sy, ey); - } - buf += sx + sy * stride; - ey -= sy; - if (ey) - f = ((ex - sx) << 16) / ey; - else - f = 0; - for(y= 0; y <= ey; y++){ - x = (y*f) >> 16; - fr = (y*f) & 0xFFFF; - buf[y * stride + x] += (color * (0x10000 - fr)) >> 16; - if(fr) buf[y * stride + x + 1] += (color * fr ) >> 16; - } - } -} - -/** - * Draw an arrow from (ex, ey) -> (sx, sy). - * @param w width of the image - * @param h height of the image - * @param stride stride/linesize of the image - * @param color color of the arrow - */ -static void draw_arrow(uint8_t *buf, int sx, int sy, int ex, - int ey, int w, int h, int stride, int color, int tail, int direction) -{ - int dx,dy; - - if (direction) { - FFSWAP(int, sx, ex); - FFSWAP(int, sy, ey); - } - - sx = av_clip(sx, -100, w + 100); - sy = av_clip(sy, -100, h + 100); - ex = av_clip(ex, -100, w + 100); - ey = av_clip(ey, -100, h + 100); - - dx = ex - sx; - dy = ey - sy; - - if (dx * dx + dy * dy > 3 * 3) { - int rx = dx + dy; - int ry = -dx + dy; - int length = ff_sqrt((rx * rx + ry * ry) << 8); - - // FIXME subpixel accuracy - rx = ROUNDED_DIV(rx * 3 << 4, length); - ry = ROUNDED_DIV(ry * 3 << 4, length); - - if (tail) { - rx = -rx; - ry = -ry; - } - - draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, stride, color); - draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, stride, color); - } - draw_line(buf, sx, sy, ex, ey, w, h, stride, color); -} -#endif - -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; -} - -/** - * 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) -{ - 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 -#if FF_API_CAP_VDPAU - || (avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) -#endif - ) - 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; - int h_chroma_shift, v_chroma_shift, block_height; -#if FF_API_VISMV - const int shift = 1 + quarter_sample; - uint8_t *ptr; - const int width = avctx->width; - const int height = avctx->height; -#endif - 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 - - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift); - - av_frame_make_writable(pict); - - pict->opaque = NULL; -#if FF_API_VISMV - ptr = pict->data[0]; -#endif - 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 FF_API_VISMV - if ((avctx->debug_mv) && motion_val[0]) { - int type; - for (type = 0; type < 3; type++) { - int direction = 0; - switch (type) { - case 0: - if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_P_FOR)) || - (pict->pict_type!= AV_PICTURE_TYPE_P)) - continue; - direction = 0; - break; - case 1: - if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_B_FOR)) || - (pict->pict_type!= AV_PICTURE_TYPE_B)) - continue; - direction = 0; - break; - case 2: - if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_B_BACK)) || - (pict->pict_type!= AV_PICTURE_TYPE_B)) - continue; - direction = 1; - break; - } - if (!USES_LIST(mbtype_table[mb_index], direction)) - continue; - - if (IS_8X8(mbtype_table[mb_index])) { - int i; - 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] >> shift) + sx; - int my = (motion_val[direction][xy][1] >> shift) + sy; - draw_arrow(ptr, sx, sy, mx, my, width, - height, pict->linesize[0], 100, 0, direction); - } - } else if (IS_16X8(mbtype_table[mb_index])) { - int i; - 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] >> shift); - int my = (motion_val[direction][xy][1] >> shift); - - if (IS_INTERLACED(mbtype_table[mb_index])) - my *= 2; - - draw_arrow(ptr, sx, sy, mx + sx, my + sy, width, - height, pict->linesize[0], 100, 0, direction); - } - } else if (IS_8X16(mbtype_table[mb_index])) { - int i; - 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] >> shift; - int my = motion_val[direction][xy][1] >> shift; - - if (IS_INTERLACED(mbtype_table[mb_index])) - my *= 2; - - draw_arrow(ptr, sx, sy, mx + sx, my + sy, width, - height, pict->linesize[0], 100, 0, 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]>>shift) + sx; - int my= (motion_val[direction][xy][1]>>shift) + sy; - draw_arrow(ptr, sx, sy, mx, my, width, height, pict->linesize[0], 100, 0, direction); - } - } - } -#endif - 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 -} - void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict) { ff_print_debug_info2(s->avctx, pict, s->mbskip_table, p->mb_type, diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index e9eb633d1..c5e335945 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -252,9 +252,6 @@ typedef struct MpegEncContext { 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]); -#if FF_API_MOTION_EST - int me_method; ///< ME algorithm -#endif int motion_est; ///< ME algorithm int me_penalty_compensation; int me_pre; ///< prepass for motion estimation @@ -699,10 +696,6 @@ 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); -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); int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type); diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 5765ef339..f1f498923 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -415,22 +415,9 @@ FF_ENABLE_DEPRECATION_WARNINGS s->intra_only = 0; } -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - s->me_method = avctx->me_method; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - /* Fixed QSCALE */ s->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->border_masking != 0.0) - s->border_masking = avctx->border_masking; - FF_ENABLE_DEPRECATION_WARNINGS -#endif - s->adaptive_quant = (s->avctx->lumi_masking || s->avctx->dark_masking || s->avctx->temporal_cplx_masking || @@ -760,15 +747,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return AVERROR(EINVAL); } -#if FF_API_QUANT_BIAS -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS) - s->intra_quant_bias = avctx->intra_quant_bias; - if (avctx->inter_quant_bias != FF_DEFAULT_QUANT_BIAS) - s->inter_quant_bias = avctx->inter_quant_bias; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - av_log(avctx, AV_LOG_DEBUG, "intra_quant_bias = %d inter_quant_bias = %d\n",s->intra_quant_bias,s->inter_quant_bias); if (avctx->codec_id == AV_CODEC_ID_MPEG4 && @@ -1043,20 +1021,9 @@ FF_ENABLE_DEPRECATION_WARNINGS 31, 0); } -#if FF_API_RC_STRATEGY -FF_DISABLE_DEPRECATION_WARNINGS - if (!s->rc_strategy) - s->rc_strategy = s->avctx->rc_strategy; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (ff_rate_control_init(s) < 0) return -1; -#if FF_API_RC_STRATEGY - av_assert0(MPV_RC_STRATEGY_XVID == FF_RC_STRATEGY_XVID); -#endif - if ((s->avctx->flags & AV_CODEC_FLAG_PASS2) && s->rc_strategy == MPV_RC_STRATEGY_XVID) { #if CONFIG_LIBXVID ret = ff_xvid_rate_control_init(s); @@ -1069,53 +1036,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; } -#if FF_API_ERROR_RATE - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->error_rate) - s->error_rate = avctx->error_rate; - FF_ENABLE_DEPRECATION_WARNINGS; -#endif - -#if FF_API_NORMALIZE_AQP - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->flags & CODEC_FLAG_NORMALIZE_AQP) - s->mpv_flags |= FF_MPV_FLAG_NAQ; - FF_ENABLE_DEPRECATION_WARNINGS; -#endif - -#if FF_API_MV0 - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->flags & CODEC_FLAG_MV0) - s->mpv_flags |= FF_MPV_FLAG_MV0; - FF_ENABLE_DEPRECATION_WARNINGS -#endif - -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->rc_qsquish != 0.0) - s->rc_qsquish = avctx->rc_qsquish; - if (avctx->rc_qmod_amp != 0.0) - s->rc_qmod_amp = avctx->rc_qmod_amp; - if (avctx->rc_qmod_freq) - s->rc_qmod_freq = avctx->rc_qmod_freq; - if (avctx->rc_buffer_aggressivity != 1.0) - s->rc_buffer_aggressivity = avctx->rc_buffer_aggressivity; - if (avctx->rc_initial_cplx != 0.0) - s->rc_initial_cplx = avctx->rc_initial_cplx; - if (avctx->lmin) - s->lmin = avctx->lmin; - if (avctx->lmax) - s->lmax = avctx->lmax; - - if (avctx->rc_eq) { - av_freep(&s->rc_eq); - s->rc_eq = av_strdup(avctx->rc_eq); - if (!s->rc_eq) - return AVERROR(ENOMEM); - } - FF_ENABLE_DEPRECATION_WARNINGS -#endif - #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->brd_scale) diff --git a/libavcodec/mpegvideo_parser.c b/libavcodec/mpegvideo_parser.c index de70cd563..be240b689 100644 --- a/libavcodec/mpegvideo_parser.c +++ b/libavcodec/mpegvideo_parser.c @@ -131,7 +131,7 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s, } } - if (!pc->progressive_sequence) { + if (!pc->progressive_sequence && !progressive_frame) { if (top_field_first) s->field_order = AV_FIELD_TT; else diff --git a/libavcodec/mpegvideo_xvmc.c b/libavcodec/mpegvideo_xvmc.c index 519a44816..f06583768 100644 --- a/libavcodec/mpegvideo_xvmc.c +++ b/libavcodec/mpegvideo_xvmc.c @@ -348,7 +348,7 @@ static void ff_xvmc_decode_mb(struct MpegEncContext *s) } #if CONFIG_MPEG1_XVMC_HWACCEL -AVHWAccel ff_mpeg1_xvmc_hwaccel = { +const AVHWAccel ff_mpeg1_xvmc_hwaccel = { .name = "mpeg1_xvmc", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG1VIDEO, @@ -362,7 +362,7 @@ AVHWAccel ff_mpeg1_xvmc_hwaccel = { #endif #if CONFIG_MPEG2_XVMC_HWACCEL -AVHWAccel ff_mpeg2_xvmc_hwaccel = { +const AVHWAccel ff_mpeg2_xvmc_hwaccel = { .name = "mpeg2_xvmc", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c index 9e7cc466d..3180af1d6 100644 --- a/libavcodec/mss2.c +++ b/libavcodec/mss2.c @@ -464,9 +464,9 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size, return 0; } -typedef struct Rectangle { +struct Rectangle { int coded, x, y, w, h; -} Rectangle; +}; #define MAX_WMV9_RECTANGLES 20 #define ARITH2_PADDING 2 @@ -485,7 +485,7 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, int keyframe, has_wmv9, has_mv, is_rle, is_555, ret; - Rectangle wmv9rects[MAX_WMV9_RECTANGLES], *r; + struct Rectangle wmv9rects[MAX_WMV9_RECTANGLES], *r; int used_rects = 0, i, implicit_rect = 0, av_uninit(wmv9_mask); if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0) diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c new file mode 100644 index 000000000..e9e6ea0f8 --- /dev/null +++ b/libavcodec/nvdec.c @@ -0,0 +1,583 @@ +/* + * HW decode acceleration through NVDEC + * + * Copyright (c) 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 "config.h" + +#include "libavutil/common.h" +#include "libavutil/error.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/pixfmt.h" + +#include "avcodec.h" +#include "decode.h" +#include "nvdec.h" +#include "internal.h" + +typedef struct NVDECDecoder { + CUvideodecoder decoder; + + AVBufferRef *hw_device_ref; + CUcontext cuda_ctx; + + CudaFunctions *cudl; + CuvidFunctions *cvdl; +} NVDECDecoder; + +typedef struct NVDECFramePool { + unsigned int dpb_size; + unsigned int nb_allocated; +} NVDECFramePool; + +static int map_avcodec_id(enum AVCodecID id) +{ + switch (id) { + case AV_CODEC_ID_H264: return cudaVideoCodec_H264; + case AV_CODEC_ID_HEVC: return cudaVideoCodec_HEVC; + case AV_CODEC_ID_MPEG1VIDEO: return cudaVideoCodec_MPEG1; + case AV_CODEC_ID_MPEG2VIDEO: return cudaVideoCodec_MPEG2; + case AV_CODEC_ID_MPEG4: return cudaVideoCodec_MPEG4; + case AV_CODEC_ID_VC1: return cudaVideoCodec_VC1; + case AV_CODEC_ID_VP8: return cudaVideoCodec_VP8; + case AV_CODEC_ID_VP9: return cudaVideoCodec_VP9; + case AV_CODEC_ID_WMV3: return cudaVideoCodec_VC1; + } + return -1; +} + +static int map_chroma_format(enum AVPixelFormat pix_fmt) +{ + int shift_h = 0, shift_v = 0; + + av_pix_fmt_get_chroma_sub_sample(pix_fmt, &shift_h, &shift_v); + + if (shift_h == 1 && shift_v == 1) + return cudaVideoChromaFormat_420; + else if (shift_h == 1 && shift_v == 0) + return cudaVideoChromaFormat_422; + else if (shift_h == 0 && shift_v == 0) + return cudaVideoChromaFormat_444; + + return -1; +} + +static int nvdec_test_capabilities(NVDECDecoder *decoder, + CUVIDDECODECREATEINFO *params, void *logctx) +{ + CUresult err; + CUVIDDECODECAPS caps = { 0 }; + + caps.eCodecType = params->CodecType; + caps.eChromaFormat = params->ChromaFormat; + caps.nBitDepthMinus8 = params->bitDepthMinus8; + + if (!decoder->cvdl->cuvidGetDecoderCaps) { + av_log(logctx, AV_LOG_WARNING, "Used Nvidia driver is too old to perform a capability check.\n"); + av_log(logctx, AV_LOG_WARNING, "The minimum required version is " +#if defined(_WIN32) || defined(__CYGWIN__) + "378.66" +#else + "378.13" +#endif + ". Continuing blind.\n"); + return 0; + } + + err = decoder->cvdl->cuvidGetDecoderCaps(&caps); + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Failed querying decoder capabilities\n"); + return AVERROR_UNKNOWN; + } + + av_log(logctx, AV_LOG_VERBOSE, "NVDEC capabilities:\n"); + av_log(logctx, AV_LOG_VERBOSE, "format supported: %s, max_mb_count: %d\n", + caps.bIsSupported ? "yes" : "no", caps.nMaxMBCount); + av_log(logctx, AV_LOG_VERBOSE, "min_width: %d, max_width: %d\n", + caps.nMinWidth, caps.nMaxWidth); + av_log(logctx, AV_LOG_VERBOSE, "min_height: %d, max_height: %d\n", + caps.nMinHeight, caps.nMaxHeight); + + if (!caps.bIsSupported) { + av_log(logctx, AV_LOG_ERROR, "Hardware is lacking required capabilities\n"); + return AVERROR(EINVAL); + } + + if (params->ulWidth > caps.nMaxWidth || params->ulWidth < caps.nMinWidth) { + av_log(logctx, AV_LOG_ERROR, "Video width %d not within range from %d to %d\n", + (int)params->ulWidth, caps.nMinWidth, caps.nMaxWidth); + return AVERROR(EINVAL); + } + + if (params->ulHeight > caps.nMaxHeight || params->ulHeight < caps.nMinHeight) { + av_log(logctx, AV_LOG_ERROR, "Video height %d not within range from %d to %d\n", + (int)params->ulHeight, caps.nMinHeight, caps.nMaxHeight); + return AVERROR(EINVAL); + } + + if ((params->ulWidth * params->ulHeight) / 256 > caps.nMaxMBCount) { + av_log(logctx, AV_LOG_ERROR, "Video macroblock count %d exceeds maximum of %d\n", + (int)(params->ulWidth * params->ulHeight) / 256, caps.nMaxMBCount); + return AVERROR(EINVAL); + } + + return 0; +} + +static void nvdec_decoder_free(void *opaque, uint8_t *data) +{ + NVDECDecoder *decoder = (NVDECDecoder*)data; + + if (decoder->decoder) + decoder->cvdl->cuvidDestroyDecoder(decoder->decoder); + + av_buffer_unref(&decoder->hw_device_ref); + + cuvid_free_functions(&decoder->cvdl); + + av_freep(&decoder); +} + +static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref, + CUVIDDECODECREATEINFO *params, void *logctx) +{ + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)hw_device_ref->data; + AVCUDADeviceContext *device_hwctx = hw_device_ctx->hwctx; + + AVBufferRef *decoder_ref; + NVDECDecoder *decoder; + + CUcontext dummy; + CUresult err; + int ret; + + decoder = av_mallocz(sizeof(*decoder)); + if (!decoder) + return AVERROR(ENOMEM); + + decoder_ref = av_buffer_create((uint8_t*)decoder, sizeof(*decoder), + nvdec_decoder_free, NULL, AV_BUFFER_FLAG_READONLY); + if (!decoder_ref) { + av_freep(&decoder); + return AVERROR(ENOMEM); + } + + decoder->hw_device_ref = av_buffer_ref(hw_device_ref); + if (!decoder->hw_device_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + decoder->cuda_ctx = device_hwctx->cuda_ctx; + decoder->cudl = device_hwctx->internal->cuda_dl; + + ret = cuvid_load_functions(&decoder->cvdl, logctx); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n"); + goto fail; + } + + err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); + if (err != CUDA_SUCCESS) { + ret = AVERROR_UNKNOWN; + goto fail; + } + + ret = nvdec_test_capabilities(decoder, params, logctx); + if (ret < 0) { + decoder->cudl->cuCtxPopCurrent(&dummy); + goto fail; + } + + err = decoder->cvdl->cuvidCreateDecoder(&decoder->decoder, params); + + decoder->cudl->cuCtxPopCurrent(&dummy); + + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Error creating a NVDEC decoder: %d\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + *out = decoder_ref; + + return 0; +fail: + av_buffer_unref(&decoder_ref); + return ret; +} + +static AVBufferRef *nvdec_decoder_frame_alloc(void *opaque, int size) +{ + NVDECFramePool *pool = opaque; + AVBufferRef *ret; + + if (pool->nb_allocated >= pool->dpb_size) + return NULL; + + ret = av_buffer_alloc(sizeof(unsigned int)); + if (!ret) + return NULL; + + *(unsigned int*)ret->data = pool->nb_allocated++; + + return ret; +} + +int ff_nvdec_decode_uninit(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + + av_freep(&ctx->bitstream); + ctx->bitstream_len = 0; + ctx->bitstream_allocated = 0; + + av_freep(&ctx->slice_offsets); + ctx->nb_slices = 0; + ctx->slice_offsets_allocated = 0; + + av_buffer_unref(&ctx->decoder_ref); + av_buffer_pool_uninit(&ctx->decoder_pool); + + return 0; +} + +int ff_nvdec_decode_init(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + + NVDECFramePool *pool; + AVHWFramesContext *frames_ctx; + const AVPixFmtDescriptor *sw_desc; + + CUVIDDECODECREATEINFO params = { 0 }; + + int cuvid_codec_type, cuvid_chroma_format; + int ret = 0; + + sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + if (!sw_desc) + return AVERROR_BUG; + + cuvid_codec_type = map_avcodec_id(avctx->codec_id); + if (cuvid_codec_type < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported codec ID\n"); + return AVERROR_BUG; + } + + cuvid_chroma_format = map_chroma_format(avctx->sw_pix_fmt); + if (cuvid_chroma_format < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported chroma format\n"); + return AVERROR(ENOSYS); + } + + if (!avctx->hw_frames_ctx) { + ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_CUDA); + if (ret < 0) + return ret; + } + + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + + params.ulWidth = avctx->coded_width; + params.ulHeight = avctx->coded_height; + params.ulTargetWidth = avctx->coded_width; + params.ulTargetHeight = avctx->coded_height; + params.bitDepthMinus8 = sw_desc->comp[0].depth - 8; + params.OutputFormat = params.bitDepthMinus8 ? + cudaVideoSurfaceFormat_P016 : cudaVideoSurfaceFormat_NV12; + params.CodecType = cuvid_codec_type; + params.ChromaFormat = cuvid_chroma_format; + params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size; + params.ulNumOutputSurfaces = 1; + + ret = nvdec_decoder_create(&ctx->decoder_ref, frames_ctx->device_ref, ¶ms, avctx); + if (ret < 0) { + if (params.ulNumDecodeSurfaces > 32) { + av_log(avctx, AV_LOG_WARNING, "Using more than 32 (%d) decode surfaces might cause nvdec to fail.\n", + (int)params.ulNumDecodeSurfaces); + av_log(avctx, AV_LOG_WARNING, "Try lowering the amount of threads. Using %d right now.\n", + avctx->thread_count); + } + return ret; + } + + pool = av_mallocz(sizeof(*pool)); + if (!pool) { + ret = AVERROR(ENOMEM); + goto fail; + } + pool->dpb_size = frames_ctx->initial_pool_size; + + ctx->decoder_pool = av_buffer_pool_init2(sizeof(int), pool, + nvdec_decoder_frame_alloc, av_free); + if (!ctx->decoder_pool) { + ret = AVERROR(ENOMEM); + goto fail; + } + + return 0; +fail: + ff_nvdec_decode_uninit(avctx); + return ret; +} + +static void nvdec_fdd_priv_free(void *priv) +{ + NVDECFrame *cf = priv; + + if (!cf) + return; + + av_buffer_unref(&cf->idx_ref); + av_buffer_unref(&cf->decoder_ref); + + av_freep(&priv); +} + +static int nvdec_retrieve_data(void *logctx, AVFrame *frame) +{ + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + NVDECFrame *cf = (NVDECFrame*)fdd->hwaccel_priv; + NVDECDecoder *decoder = (NVDECDecoder*)cf->decoder_ref->data; + + CUVIDPROCPARAMS vpp = { .progressive_frame = 1 }; + + CUresult err; + CUcontext dummy; + CUdeviceptr devptr; + + unsigned int pitch, i; + unsigned int offset = 0; + int ret = 0; + + err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); + if (err != CUDA_SUCCESS) + return AVERROR_UNKNOWN; + + err = decoder->cvdl->cuvidMapVideoFrame(decoder->decoder, cf->idx, &devptr, + &pitch, &vpp); + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Error mapping a picture with CUVID: %d\n", + err); + ret = AVERROR_UNKNOWN; + goto finish; + } + + for (i = 0; frame->data[i]; i++) { + CUDA_MEMCPY2D cpy = { + .srcMemoryType = CU_MEMORYTYPE_DEVICE, + .dstMemoryType = CU_MEMORYTYPE_DEVICE, + .srcDevice = devptr, + .dstDevice = (CUdeviceptr)frame->data[i], + .srcPitch = pitch, + .dstPitch = frame->linesize[i], + .srcY = offset, + .WidthInBytes = FFMIN(pitch, frame->linesize[i]), + .Height = frame->height >> (i ? 1 : 0), + }; + + err = decoder->cudl->cuMemcpy2D(&cpy); + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Error copying decoded frame: %d\n", + err); + ret = AVERROR_UNKNOWN; + goto copy_fail; + } + + offset += cpy.Height; + } + +copy_fail: + decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr); + +finish: + decoder->cudl->cuCtxPopCurrent(&dummy); + return ret; +} + +int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + NVDECFrame *cf = NULL; + int ret; + + ctx->bitstream_len = 0; + ctx->nb_slices = 0; + + if (fdd->hwaccel_priv) + return 0; + + cf = av_mallocz(sizeof(*cf)); + if (!cf) + return AVERROR(ENOMEM); + + cf->decoder_ref = av_buffer_ref(ctx->decoder_ref); + if (!cf->decoder_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + + cf->idx_ref = av_buffer_pool_get(ctx->decoder_pool); + if (!cf->idx_ref) { + av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n"); + ret = AVERROR(ENOMEM); + goto fail; + } + cf->idx = *(unsigned int*)cf->idx_ref->data; + + fdd->hwaccel_priv = cf; + fdd->hwaccel_priv_free = nvdec_fdd_priv_free; + fdd->post_process = nvdec_retrieve_data; + + return 0; +fail: + nvdec_fdd_priv_free(cf); + return ret; + +} + +int ff_nvdec_end_frame(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + NVDECDecoder *decoder = (NVDECDecoder*)ctx->decoder_ref->data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + + CUresult err; + CUcontext dummy; + + int ret = 0; + + pp->nBitstreamDataLen = ctx->bitstream_len; + pp->pBitstreamData = ctx->bitstream; + pp->nNumSlices = ctx->nb_slices; + pp->pSliceDataOffsets = ctx->slice_offsets; + + err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); + if (err != CUDA_SUCCESS) + return AVERROR_UNKNOWN; + + err = decoder->cvdl->cuvidDecodePicture(decoder->decoder, &ctx->pic_params); + if (err != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error decoding a picture with NVDEC: %d\n", + err); + ret = AVERROR_UNKNOWN; + goto finish; + } + +finish: + decoder->cudl->cuCtxPopCurrent(&dummy); + + return ret; +} + +int ff_nvdec_simple_end_frame(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + int ret = ff_nvdec_end_frame(avctx); + ctx->bitstream = NULL; + return ret; +} + +int ff_nvdec_simple_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + void *tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + if (!ctx->bitstream) + ctx->bitstream = (uint8_t*)buffer; + + ctx->slice_offsets[ctx->nb_slices] = buffer - ctx->bitstream; + ctx->bitstream_len += size; + ctx->nb_slices++; + + return 0; +} + +int ff_nvdec_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx, + int dpb_size) +{ + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; + const AVPixFmtDescriptor *sw_desc; + int cuvid_codec_type, cuvid_chroma_format; + + sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + if (!sw_desc) + return AVERROR_BUG; + + cuvid_codec_type = map_avcodec_id(avctx->codec_id); + if (cuvid_codec_type < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported codec ID\n"); + return AVERROR_BUG; + } + + cuvid_chroma_format = map_chroma_format(avctx->sw_pix_fmt); + if (cuvid_chroma_format < 0) { + av_log(avctx, AV_LOG_VERBOSE, "Unsupported chroma format\n"); + return AVERROR(EINVAL); + } + + frames_ctx->format = AV_PIX_FMT_CUDA; + frames_ctx->width = (avctx->coded_width + 1) & ~1; + frames_ctx->height = (avctx->coded_height + 1) & ~1; + frames_ctx->initial_pool_size = dpb_size; + + switch (sw_desc->comp[0].depth) { + case 8: + frames_ctx->sw_format = AV_PIX_FMT_NV12; + break; + case 10: + frames_ctx->sw_format = AV_PIX_FMT_P010; + break; + case 12: + frames_ctx->sw_format = AV_PIX_FMT_P016; + break; + default: + return AVERROR(EINVAL); + } + + return 0; +} + +int ff_nvdec_get_ref_idx(AVFrame *frame) +{ + FrameDecodeData *fdd; + NVDECFrame *cf; + + if (!frame || !frame->private_ref) + return -1; + + fdd = (FrameDecodeData*)frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + if (!cf) + return -1; + + return cf->idx; +} diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h new file mode 100644 index 000000000..90578d5a1 --- /dev/null +++ b/libavcodec/nvdec.h @@ -0,0 +1,69 @@ +/* + * HW decode acceleration through NVDEC + * + * Copyright (c) 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 + */ + +#ifndef AVCODEC_NVDEC_H +#define AVCODEC_NVDEC_H + +#include "compat/cuda/dynlink_loader.h" + +#include + +#include "libavutil/buffer.h" +#include "libavutil/frame.h" + +#include "avcodec.h" + +typedef struct NVDECFrame { + unsigned int idx; + AVBufferRef *idx_ref; + AVBufferRef *decoder_ref; +} NVDECFrame; + +typedef struct NVDECContext { + CUVIDPICPARAMS pic_params; + + AVBufferPool *decoder_pool; + + AVBufferRef *decoder_ref; + + uint8_t *bitstream; + int bitstream_len; + unsigned int bitstream_allocated; + + unsigned *slice_offsets; + int nb_slices; + unsigned int slice_offsets_allocated; +} NVDECContext; + +int ff_nvdec_decode_init(AVCodecContext *avctx); +int ff_nvdec_decode_uninit(AVCodecContext *avctx); +int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame); +int ff_nvdec_end_frame(AVCodecContext *avctx); +int ff_nvdec_simple_end_frame(AVCodecContext *avctx); +int ff_nvdec_simple_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size); +int ff_nvdec_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx, + int dpb_size); +int ff_nvdec_get_ref_idx(AVFrame *frame); + +#endif /* AVCODEC_NVDEC_H */ diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c new file mode 100644 index 000000000..35f54f2ed --- /dev/null +++ b/libavcodec/nvdec_h264.c @@ -0,0 +1,178 @@ +/* + * MPEG-4 Part 10 / AVC / H.264 HW decode acceleration through NVDEC + * + * Copyright (c) 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 +#include + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "h264dec.h" + +static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Picture *src, + int frame_idx) +{ + FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; + const NVDECFrame *cf = fdd->hwaccel_priv; + + dst->PicIdx = cf ? cf->idx : -1; + dst->FrameIdx = frame_idx; + dst->is_long_term = src->long_ref; + dst->not_existing = 0; + dst->used_for_reference = src->reference & 3; + dst->FieldOrderCnt[0] = src->field_poc[0]; + dst->FieldOrderCnt[1] = src->field_poc[1]; +} + +static int nvdec_h264_start_frame(AVCodecContext *avctx, + const uint8_t *buffer, uint32_t size) +{ + const H264Context *h = avctx->priv_data; + const PPS *pps = h->ps.pps; + const SPS *sps = h->ps.sps; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDH264PICPARAMS *ppc = &pp->CodecSpecific.h264; + FrameDecodeData *fdd; + NVDECFrame *cf; + + int i, dpb_size, ret; + + ret = ff_nvdec_start_frame(avctx, h->cur_pic_ptr->f); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)h->cur_pic_ptr->f->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = h->mb_width, + .FrameHeightInMbs = h->mb_height, + .CurrPicIdx = cf->idx, + .field_pic_flag = FIELD_PICTURE(h), + .bottom_field_flag = h->picture_structure == PICT_BOTTOM_FIELD, + .second_field = FIELD_PICTURE(h) && !h->first_field, + .ref_pic_flag = h->nal_ref_idc != 0, + .intra_pic_flag = 0, + + .CodecSpecific.h264 = { + .log2_max_frame_num_minus4 = sps->log2_max_frame_num - 4, + .pic_order_cnt_type = sps->poc_type, + .log2_max_pic_order_cnt_lsb_minus4 = FFMAX(sps->log2_max_poc_lsb - 4, 0), + .delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag, + .frame_mbs_only_flag = sps->frame_mbs_only_flag, + .direct_8x8_inference_flag = sps->direct_8x8_inference_flag, + .num_ref_frames = sps->ref_frame_count, + .residual_colour_transform_flag = sps->residual_color_transform_flag, + .bit_depth_luma_minus8 = sps->bit_depth_luma - 8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma - 8, + .qpprime_y_zero_transform_bypass_flag = sps->transform_bypass, + + .entropy_coding_mode_flag = pps->cabac, + .pic_order_present_flag = pps->pic_order_present, + .num_ref_idx_l0_active_minus1 = pps->ref_count[0] - 1, + .num_ref_idx_l1_active_minus1 = pps->ref_count[1] - 1, + .weighted_pred_flag = pps->weighted_pred, + .weighted_bipred_idc = pps->weighted_bipred_idc, + .pic_init_qp_minus26 = pps->init_qp - 26, + .deblocking_filter_control_present_flag = pps->deblocking_filter_parameters_present, + .redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present, + .transform_8x8_mode_flag = pps->transform_8x8_mode, + .MbaffFrameFlag = sps->mb_aff && !FIELD_PICTURE(h), + .constrained_intra_pred_flag = pps->constrained_intra_pred, + .chroma_qp_index_offset = pps->chroma_qp_index_offset[0], + .second_chroma_qp_index_offset = pps->chroma_qp_index_offset[1], + .ref_pic_flag = h->nal_ref_idc != 0, + .frame_num = h->poc.frame_num, + .CurrFieldOrderCnt[0] = h->cur_pic_ptr->field_poc[0], + .CurrFieldOrderCnt[1] = h->cur_pic_ptr->field_poc[1], + }, + }; + + memcpy(ppc->WeightScale4x4, pps->scaling_matrix4, sizeof(ppc->WeightScale4x4)); + memcpy(ppc->WeightScale8x8[0], pps->scaling_matrix8[0], sizeof(ppc->WeightScale8x8[0])); + memcpy(ppc->WeightScale8x8[1], pps->scaling_matrix8[3], sizeof(ppc->WeightScale8x8[0])); + + dpb_size = 0; + for (i = 0; i < h->short_ref_count; i++) + dpb_add(h, &ppc->dpb[dpb_size++], h->short_ref[i], h->short_ref[i]->frame_num); + for (i = 0; i < 16; i++) { + if (h->long_ref[i]) + dpb_add(h, &ppc->dpb[dpb_size++], h->long_ref[i], i); + } + + for (i = dpb_size; i < FF_ARRAY_ELEMS(ppc->dpb); i++) + ppc->dpb[i].PicIdx = -1; + + return 0; +} + +static int nvdec_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + void *tmp; + + tmp = av_fast_realloc(ctx->bitstream, &ctx->bitstream_allocated, + ctx->bitstream_len + size + 3); + if (!tmp) + return AVERROR(ENOMEM); + ctx->bitstream = tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + AV_WB24(ctx->bitstream + ctx->bitstream_len, 1); + memcpy(ctx->bitstream + ctx->bitstream_len + 3, buffer, size); + ctx->slice_offsets[ctx->nb_slices] = ctx->bitstream_len ; + ctx->bitstream_len += size + 3; + ctx->nb_slices++; + + return 0; +} + +static int nvdec_h264_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + const H264Context *h = avctx->priv_data; + const SPS *sps = h->ps.sps; + return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->ref_frame_count + sps->num_reorder_frames); +} + +const AVHWAccel ff_h264_nvdec_hwaccel = { + .name = "h264_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_h264_start_frame, + .end_frame = ff_nvdec_end_frame, + .decode_slice = nvdec_h264_decode_slice, + .frame_params = nvdec_h264_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c new file mode 100644 index 000000000..58f3fa9b4 --- /dev/null +++ b/libavcodec/nvdec_hevc.c @@ -0,0 +1,281 @@ +/* + * HEVC HW decode acceleration through NVDEC + * + * Copyright (c) 2017 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 +#include + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "hevcdec.h" +#include "hevc_data.h" + +static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src) +{ + FrameDecodeData *fdd = (FrameDecodeData*)src->frame->private_ref->data; + const NVDECFrame *cf = fdd->hwaccel_priv; + + pp->RefPicIdx[idx] = cf ? cf->idx : -1; + pp->PicOrderCntVal[idx] = src->poc; + pp->IsLongTerm[idx] = !!(src->flags & HEVC_FRAME_FLAG_LONG_REF); +} + +static void fill_scaling_lists(CUVIDHEVCPICPARAMS *ppc, const HEVCContext *s) +{ + const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ? + &s->ps.pps->scaling_list : &s->ps.sps->scaling_list; + int i, j, pos; + + for (i = 0; i < 6; i++) { + for (j = 0; j < 16; j++) { + pos = 4 * ff_hevc_diag_scan4x4_y[j] + ff_hevc_diag_scan4x4_x[j]; + ppc->ScalingList4x4[i][j] = sl->sl[0][i][pos]; + } + + for (j = 0; j < 64; j++) { + pos = 8 * ff_hevc_diag_scan8x8_y[j] + ff_hevc_diag_scan8x8_x[j]; + ppc->ScalingList8x8[i][j] = sl->sl[1][i][pos]; + ppc->ScalingList16x16[i][j] = sl->sl[2][i][pos]; + + if (i < 2) + ppc->ScalingList32x32[i][j] = sl->sl[3][i][pos]; + } + } + + memcpy(ppc->ScalingListDCCoeff16x16, sl->sl_dc[0], sizeof(ppc->ScalingListDCCoeff16x16)); + memcpy(ppc->ScalingListDCCoeff32x32, sl->sl_dc[1], sizeof(ppc->ScalingListDCCoeff32x32)); +} + +static int nvdec_hevc_start_frame(AVCodecContext *avctx, + const uint8_t *buffer, uint32_t size) +{ + const HEVCContext *s = avctx->priv_data; + const HEVCPPS *pps = s->ps.pps; + const HEVCSPS *sps = s->ps.sps; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDHEVCPICPARAMS *ppc = &pp->CodecSpecific.hevc; + FrameDecodeData *fdd; + NVDECFrame *cf; + + int i, j, dpb_size, ret; + + ret = ff_nvdec_start_frame(avctx, s->ref->frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)s->ref->frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = sps->width / 16, + .FrameHeightInMbs = sps->height / 16, + .CurrPicIdx = cf->idx, + .ref_pic_flag = 1, + .intra_pic_flag = 0, + + .CodecSpecific.hevc = { + .pic_width_in_luma_samples = sps->width, + .pic_height_in_luma_samples = sps->height, + .log2_min_luma_coding_block_size_minus3 = sps->log2_min_cb_size - 3, + .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_coding_block_size, + .log2_min_transform_block_size_minus2 = sps->log2_min_tb_size - 2, + .log2_diff_max_min_transform_block_size = sps->log2_max_trafo_size - sps->log2_min_tb_size, + .pcm_enabled_flag = sps->pcm_enabled_flag, + .log2_min_pcm_luma_coding_block_size_minus3 = sps->pcm_enabled_flag ? sps->pcm.log2_min_pcm_cb_size - 3 : 0, + .log2_diff_max_min_pcm_luma_coding_block_size = sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size, + .pcm_sample_bit_depth_luma_minus1 = sps->pcm_enabled_flag ? sps->pcm.bit_depth - 1 : 0, + .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_enabled_flag ? sps->pcm.bit_depth_chroma - 1 : 0, + .pcm_loop_filter_disabled_flag = sps->pcm.loop_filter_disable_flag, + .strong_intra_smoothing_enabled_flag = sps->sps_strong_intra_smoothing_enable_flag, + .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra, + .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter, + .amp_enabled_flag = sps->amp_enabled_flag, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_poc_lsb - 4, + .num_short_term_ref_pic_sets = sps->nb_st_rps, + .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag, + .num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps, + .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + .sample_adaptive_offset_enabled_flag = sps->sao_enabled, + .scaling_list_enable_flag = sps->scaling_list_enable_flag, + .IrapPicFlag = IS_IRAP(s), + .IdrPicFlag = IS_IDR(s), + .bit_depth_luma_minus8 = sps->bit_depth - 8, + .bit_depth_chroma_minus8 = sps->bit_depth - 8, + + .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag, + .slice_segment_header_extension_present_flag = pps->slice_header_extension_present_flag, + .sign_data_hiding_enabled_flag = pps->sign_data_hiding_flag, + .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, + .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, + .init_qp_minus26 = pps->pic_init_qp_minus26, + .pps_cb_qp_offset = pps->cb_qp_offset, + .pps_cr_qp_offset = pps->cr_qp_offset, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_flag = pps->weighted_bipred_flag, + .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, + .transquant_bypass_enabled_flag = pps->transquant_bypass_enable_flag, + .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, + .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level - 2, + .num_extra_slice_header_bits = pps->num_extra_slice_header_bits, + .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag, + .loop_filter_across_slices_enabled_flag = pps->seq_loop_filter_across_slices_enabled_flag, + .output_flag_present_flag = pps->output_flag_present_flag, + .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active - 1, + .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active - 1, + .lists_modification_present_flag = pps->lists_modification_present_flag, + .cabac_init_present_flag = pps->cabac_init_present_flag, + .pps_slice_chroma_qp_offsets_present_flag = pps->pic_slice_level_chroma_qp_offsets_present_flag, + .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag, + .pps_deblocking_filter_disabled_flag = pps->disable_dbf, + .pps_beta_offset_div2 = pps->beta_offset / 2, + .pps_tc_offset_div2 = pps->tc_offset / 2, + .tiles_enabled_flag = pps->tiles_enabled_flag, + .uniform_spacing_flag = pps->uniform_spacing_flag, + .num_tile_columns_minus1 = pps->num_tile_columns - 1, + .num_tile_rows_minus1 = pps->num_tile_rows - 1, + + .NumBitsForShortTermRPSInSlice = s->sh.short_term_rps ? s->sh.short_term_ref_pic_set_size : 0, + .NumDeltaPocsOfRefRpsIdx = s->sh.short_term_rps ? s->sh.short_term_rps->rps_idx_num_delta_pocs : 0, + .NumPocTotalCurr = s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs + + s->rps[LT_CURR].nb_refs, + .NumPocStCurrBefore = s->rps[ST_CURR_BEF].nb_refs, + .NumPocStCurrAfter = s->rps[ST_CURR_AFT].nb_refs, + .NumPocLtCurr = s->rps[LT_CURR].nb_refs, + .CurrPicOrderCntVal = s->ref->poc, + }, + }; + + if (pps->num_tile_columns > FF_ARRAY_ELEMS(ppc->column_width_minus1) || + pps->num_tile_rows > FF_ARRAY_ELEMS(ppc->row_height_minus1)) { + av_log(avctx, AV_LOG_ERROR, "Too many tiles\n"); + return AVERROR(ENOSYS); + } + for (i = 0; i < pps->num_tile_columns; i++) + ppc->column_width_minus1[i] = pps->column_width[i] - 1; + for (i = 0; i < pps->num_tile_rows; i++) + ppc->row_height_minus1[i] = pps->row_height[i] - 1; + + if (s->rps[LT_CURR].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetLtCurr) || + s->rps[ST_CURR_BEF].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetStCurrBefore) || + s->rps[ST_CURR_AFT].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetStCurrAfter)) { + av_log(avctx, AV_LOG_ERROR, "Too many reference frames\n"); + return AVERROR(ENOSYS); + } + + dpb_size = 0; + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + const HEVCFrame *ref = &s->DPB[i]; + if (!(ref->flags & (HEVC_FRAME_FLAG_SHORT_REF | HEVC_FRAME_FLAG_LONG_REF))) + continue; + if (dpb_size >= FF_ARRAY_ELEMS(ppc->RefPicIdx)) { + av_log(avctx, AV_LOG_ERROR, "Too many reference frames\n"); + return AVERROR_INVALIDDATA; + } + dpb_add(ppc, dpb_size++, ref); + + } + for (i = dpb_size; i < FF_ARRAY_ELEMS(ppc->RefPicIdx); i++) + ppc->RefPicIdx[i] = -1; + + for (i = 0; i < s->rps[ST_CURR_BEF].nb_refs; i++) { + for (j = 0; j < dpb_size; j++) { + if (ppc->PicOrderCntVal[j] == s->rps[ST_CURR_BEF].list[i]) { + ppc->RefPicSetStCurrBefore[i] = j; + break; + } + } + } + for (i = 0; i < s->rps[ST_CURR_AFT].nb_refs; i++) { + for (j = 0; j < dpb_size; j++) { + if (ppc->PicOrderCntVal[j] == s->rps[ST_CURR_AFT].list[i]) { + ppc->RefPicSetStCurrAfter[i] = j; + break; + } + } + } + for (i = 0; i < s->rps[LT_CURR].nb_refs; i++) { + for (j = 0; j < dpb_size; j++) { + if (ppc->PicOrderCntVal[j] == s->rps[LT_CURR].list[i]) { + ppc->RefPicSetLtCurr[i] = j; + break; + } + } + } + + fill_scaling_lists(ppc, s); + + return 0; +} + +static int nvdec_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + void *tmp; + + tmp = av_fast_realloc(ctx->bitstream, &ctx->bitstream_allocated, + ctx->bitstream_len + size + 3); + if (!tmp) + return AVERROR(ENOMEM); + ctx->bitstream = tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + AV_WB24(ctx->bitstream + ctx->bitstream_len, 1); + memcpy(ctx->bitstream + ctx->bitstream_len + 3, buffer, size); + ctx->slice_offsets[ctx->nb_slices] = ctx->bitstream_len ; + ctx->bitstream_len += size + 3; + ctx->nb_slices++; + + return 0; +} + +static int nvdec_hevc_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + const HEVCContext *s = avctx->priv_data; + const HEVCSPS *sps = s->ps.sps; + return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering + 1); +} + +const AVHWAccel ff_hevc_nvdec_hwaccel = { + .name = "hevc_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_hevc_start_frame, + .end_frame = ff_nvdec_end_frame, + .decode_slice = nvdec_hevc_decode_slice, + .frame_params = nvdec_hevc_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c new file mode 100644 index 000000000..7293d5055 --- /dev/null +++ b/libavcodec/nvdec_mpeg12.c @@ -0,0 +1,123 @@ +/* + * MPEG-1/2 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "mpegvideo.h" +#include "nvdec.h" +#include "decode.h" + +static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + MpegEncContext *s = avctx->priv_data; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDMPEG2PICPARAMS *ppc = &pp->CodecSpecific.mpeg2; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->current_picture.f; + + int ret, i; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P, + + .CodecSpecific.mpeg2 = { + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + + .picture_coding_type = s->pict_type, + .full_pel_forward_vector = s->full_pel[0], + .full_pel_backward_vector = s->full_pel[1], + .f_code = { { s->mpeg_f_code[0][0], + s->mpeg_f_code[0][1] }, + { s->mpeg_f_code[1][0], + s->mpeg_f_code[1][1] } }, + .intra_dc_precision = s->intra_dc_precision, + .frame_pred_frame_dct = s->frame_pred_frame_dct, + .concealment_motion_vectors = s->concealment_motion_vectors, + .q_scale_type = s->q_scale_type, + .intra_vlc_format = s->intra_vlc_format, + .alternate_scan = s->alternate_scan, + .top_field_first = s->top_field_first, + } + }; + + for (i = 0; i < 64; ++i) { + ppc->QuantMatrixIntra[i] = s->intra_matrix[i]; + ppc->QuantMatrixInter[i] = s->inter_matrix[i]; + } + + return 0; +} + +static int nvdec_mpeg12_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Each frame can at most have one P and one B reference + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); +} + +#if CONFIG_MPEG2_NVDEC_HWACCEL +const AVHWAccel ff_mpeg2_nvdec_hwaccel = { + .name = "mpeg2_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG2VIDEO, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mpeg12_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_mpeg12_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif + +#if CONFIG_MPEG1_NVDEC_HWACCEL +const AVHWAccel ff_mpeg1_nvdec_hwaccel = { + .name = "mpeg1_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG1VIDEO, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mpeg12_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_mpeg12_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c new file mode 100644 index 000000000..907af1391 --- /dev/null +++ b/libavcodec/nvdec_mpeg4.c @@ -0,0 +1,121 @@ +/* + * MPEG-4 Part 2 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "mpeg4video.h" +#include "nvdec.h" +#include "decode.h" + +static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + Mpeg4DecContext *m = avctx->priv_data; + MpegEncContext *s = &m->m; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDMPEG4PICPARAMS *ppc = &pp->CodecSpecific.mpeg4; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->current_picture.f; + + int ret, i; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P || + s->pict_type == AV_PICTURE_TYPE_S, + + .CodecSpecific.mpeg4 = { + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + + .video_object_layer_width = s->width, + .video_object_layer_height = s->height, + .vop_time_increment_bitcount = m->time_increment_bits, + .top_field_first = s->top_field_first, + .resync_marker_disable = !m->resync_marker, + .quant_type = s->mpeg_quant, + .quarter_sample = s->quarter_sample, + .short_video_header = avctx->codec->id == AV_CODEC_ID_H263, + .divx_flags = s->divx_packed ? 5 : 0, + + .vop_coding_type = s->pict_type - AV_PICTURE_TYPE_I, + .vop_coded = 1, + .vop_rounding_type = s->no_rounding, + .alternate_vertical_scan_flag = s->alternate_scan, + .interlaced = !s->progressive_sequence, + .vop_fcode_forward = s->f_code, + .vop_fcode_backward = s->b_code, + .trd = { s->pp_time, s->pp_field_time >> 1 }, + .trb = { s->pb_time, s->pb_field_time >> 1 }, + + .gmc_enabled = s->pict_type == AV_PICTURE_TYPE_S && + m->vol_sprite_usage == GMC_SPRITE, + } + }; + + for (i = 0; i < 64; ++i) { + ppc->QuantMatrixIntra[i] = s->intra_matrix[i]; + ppc->QuantMatrixInter[i] = s->inter_matrix[i]; + } + + // We need to pass the full frame buffer and not just the slice + return ff_nvdec_simple_decode_slice(avctx, buffer, size); +} + +static int nvdec_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + return 0; +} + +static int nvdec_mpeg4_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Each frame can at most have one P and one B reference + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); +} + +const AVHWAccel ff_mpeg4_nvdec_hwaccel = { + .name = "mpeg4_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG4, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mpeg4_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = nvdec_mpeg4_decode_slice, + .frame_params = nvdec_mpeg4_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c new file mode 100644 index 000000000..7257692d6 --- /dev/null +++ b/libavcodec/nvdec_vc1.c @@ -0,0 +1,141 @@ +/* + * VC1 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "nvdec.h" +#include "decode.h" +#include "vc1.h" + +static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + VC1Context *v = avctx->priv_data; + MpegEncContext *s = &v->s; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->current_picture.f; + + int ret; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + .field_pic_flag = v->field_mode, + .bottom_field_flag = v->cur_field_type, + .second_field = v->second_field, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_BI, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P, + + .CodecSpecific.vc1 = { + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + .FrameWidth = cur_frame->width, + .FrameHeight = cur_frame->height, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_BI, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P, + .progressive_fcm = v->fcm == 0, + + .profile = v->profile, + .postprocflag = v->postprocflag, + .pulldown = v->broadcast, + .interlace = v->interlace, + .tfcntrflag = v->tfcntrflag, + .finterpflag = v->finterpflag, + .psf = v->psf, + .multires = v->multires, + .syncmarker = v->resync_marker, + .rangered = v->rangered, + .maxbframes = s->max_b_frames, + + .panscan_flag = v->panscanflag, + .refdist_flag = v->refdist_flag, + .extended_mv = v->extended_mv, + .dquant = v->dquant, + .vstransform = v->vstransform, + .loopfilter = v->s.loop_filter, + .fastuvmc = v->fastuvmc, + .overlap = v->overlap, + .quantizer = v->quantizer_mode, + .extended_dmv = v->extended_dmv, + .range_mapy_flag = v->range_mapy_flag, + .range_mapy = v->range_mapy, + .range_mapuv_flag = v->range_mapuv_flag, + .range_mapuv = v->range_mapuv, + .rangeredfrm = v->rangeredfrm, + } + }; + + return 0; +} + +static int nvdec_vc1_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Each frame can at most have one P and one B reference + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); +} + +const AVHWAccel ff_vc1_nvdec_hwaccel = { + .name = "vc1_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VC1, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vc1_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vc1_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; + +#if CONFIG_WMV3_NVDEC_HWACCEL +const AVHWAccel ff_wmv3_nvdec_hwaccel = { + .name = "wmv3_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_WMV3, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vc1_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vc1_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif diff --git a/libavcodec/nvdec_vp8.c b/libavcodec/nvdec_vp8.c new file mode 100644 index 000000000..7b3744561 --- /dev/null +++ b/libavcodec/nvdec_vp8.c @@ -0,0 +1,105 @@ +/* + * VP8 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "vp8.h" + +static unsigned char safe_get_ref_idx(VP8Frame *frame) +{ + return frame ? ff_nvdec_get_ref_idx(frame->tf.f) : 255; +} + +static int nvdec_vp8_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + VP8Context *h = avctx->priv_data; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = h->framep[VP56_FRAME_CURRENT]->tf.f; + + int ret; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .CodecSpecific.vp8 = { + .width = cur_frame->width, + .height = cur_frame->height, + + .first_partition_size = h->header_partition_size, + + .LastRefIdx = safe_get_ref_idx(h->framep[VP56_FRAME_PREVIOUS]), + .GoldenRefIdx = safe_get_ref_idx(h->framep[VP56_FRAME_GOLDEN]), + .AltRefIdx = safe_get_ref_idx(h->framep[VP56_FRAME_GOLDEN2]), + /* + * Explicit braces for anonymous inners and unnamed fields + * to work around limitations in ancient versions of gcc. + */ + { // union + { // struct + !h->keyframe, // frame_type + h->profile, // version + !h->invisible, // show_frame + h->segmentation.enabled ? // update_mb_segmentation_data + h->segmentation.update_feature_data : 0, + } + } + } + }; + + return 0; +} + +static int nvdec_vp8_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // VP8 uses a fixed size pool of 3 possible reference frames + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 3); +} + +AVHWAccel ff_vp8_nvdec_hwaccel = { + .name = "vp8_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP8, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vp8_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vp8_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_vp9.c b/libavcodec/nvdec_vp9.c new file mode 100644 index 000000000..3b665a9bc --- /dev/null +++ b/libavcodec/nvdec_vp9.c @@ -0,0 +1,184 @@ +/* + * VP9 HW decode acceleration through NVDEC + * + * Copyright (c) 2016 Timo Rothenpieler + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/pixdesc.h" + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "vp9shared.h" + +static int nvdec_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + VP9SharedContext *h = avctx->priv_data; + const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDVP9PICPARAMS *ppc = &pp->CodecSpecific.vp9; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = h->frames[CUR_FRAME].tf.f; + + int ret, i; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .CodecSpecific.vp9 = { + .width = cur_frame->width, + .height = cur_frame->height, + + .LastRefIdx = ff_nvdec_get_ref_idx(h->refs[h->h.refidx[0]].f), + .GoldenRefIdx = ff_nvdec_get_ref_idx(h->refs[h->h.refidx[1]].f), + .AltRefIdx = ff_nvdec_get_ref_idx(h->refs[h->h.refidx[2]].f), + + .profile = h->h.profile, + .frameContextIdx = h->h.framectxid, + .frameType = !h->h.keyframe, + .showFrame = !h->h.invisible, + .errorResilient = h->h.errorres, + .frameParallelDecoding = h->h.parallelmode, + .subSamplingX = pixdesc->log2_chroma_w, + .subSamplingY = pixdesc->log2_chroma_h, + .intraOnly = h->h.intraonly, + .allow_high_precision_mv = h->h.keyframe ? 0 : h->h.highprecisionmvs, + .refreshEntropyProbs = h->h.refreshctx, + + .bitDepthMinus8Luma = pixdesc->comp[0].depth - 8, + .bitDepthMinus8Chroma = pixdesc->comp[1].depth - 8, + + .loopFilterLevel = h->h.filter.level, + .loopFilterSharpness = h->h.filter.sharpness, + .modeRefLfEnabled = h->h.lf_delta.enabled, + + .log2_tile_columns = h->h.tiling.log2_tile_cols, + .log2_tile_rows = h->h.tiling.log2_tile_rows, + + .segmentEnabled = h->h.segmentation.enabled, + .segmentMapUpdate = h->h.segmentation.update_map, + .segmentMapTemporalUpdate = h->h.segmentation.temporal, + .segmentFeatureMode = h->h.segmentation.absolute_vals, + + .qpYAc = h->h.yac_qi, + .qpYDc = h->h.ydc_qdelta, + .qpChDc = h->h.uvdc_qdelta, + .qpChAc = h->h.uvac_qdelta, + + .resetFrameContext = h->h.resetctx, + .mcomp_filter_type = h->h.filtermode ^ (h->h.filtermode <= 1), + + .frameTagSize = h->h.uncompressed_header_size, + .offsetToDctParts = h->h.compressed_header_size, + + .refFrameSignBias[0] = 0, + } + }; + + for (i = 0; i < 2; i++) + ppc->mbModeLfDelta[i] = h->h.lf_delta.mode[i]; + + for (i = 0; i < 4; i++) + ppc->mbRefLfDelta[i] = h->h.lf_delta.ref[i]; + + for (i = 0; i < 7; i++) + ppc->mb_segment_tree_probs[i] = h->h.segmentation.prob[i]; + + for (i = 0; i < 3; i++) { + ppc->activeRefIdx[i] = h->h.refidx[i]; + ppc->segment_pred_probs[i] = h->h.segmentation.pred_prob[i]; + ppc->refFrameSignBias[i + 1] = h->h.signbias[i]; + } + + for (i = 0; i < 8; i++) { + ppc->segmentFeatureEnable[i][0] = h->h.segmentation.feat[i].q_enabled; + ppc->segmentFeatureEnable[i][1] = h->h.segmentation.feat[i].lf_enabled; + ppc->segmentFeatureEnable[i][2] = h->h.segmentation.feat[i].ref_enabled; + ppc->segmentFeatureEnable[i][3] = h->h.segmentation.feat[i].skip_enabled; + + ppc->segmentFeatureData[i][0] = h->h.segmentation.feat[i].q_val; + ppc->segmentFeatureData[i][1] = h->h.segmentation.feat[i].lf_val; + ppc->segmentFeatureData[i][2] = h->h.segmentation.feat[i].ref_val; + ppc->segmentFeatureData[i][3] = 0; + } + + switch (avctx->colorspace) { + default: + case AVCOL_SPC_UNSPECIFIED: + ppc->colorSpace = 0; + break; + case AVCOL_SPC_BT470BG: + ppc->colorSpace = 1; + break; + case AVCOL_SPC_BT709: + ppc->colorSpace = 2; + break; + case AVCOL_SPC_SMPTE170M: + ppc->colorSpace = 3; + break; + case AVCOL_SPC_SMPTE240M: + ppc->colorSpace = 4; + break; + case AVCOL_SPC_BT2020_NCL: + ppc->colorSpace = 5; + break; + case AVCOL_SPC_RESERVED: + ppc->colorSpace = 6; + break; + case AVCOL_SPC_RGB: + ppc->colorSpace = 7; + break; + } + + return 0; +} + +static int nvdec_vp9_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // VP9 uses a fixed size pool of 8 possible reference frames + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 8); +} + +const AVHWAccel ff_vp9_nvdec_hwaccel = { + .name = "vp9_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP9, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vp9_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vp9_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index e1d3316de..4a91d9972 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -45,6 +45,9 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_0RGB32, AV_PIX_FMT_0BGR32, AV_PIX_FMT_CUDA, +#if CONFIG_D3D11VA + AV_PIX_FMT_D3D11, +#endif AV_PIX_FMT_NONE }; @@ -130,11 +133,11 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) uint32_t nvenc_max_ver; int ret; - ret = cuda_load_functions(&dl_fn->cuda_dl); + ret = cuda_load_functions(&dl_fn->cuda_dl, avctx); if (ret < 0) return ret; - ret = nvenc_load_functions(&dl_fn->nvenc_dl); + ret = nvenc_load_functions(&dl_fn->nvenc_dl, avctx); if (ret < 0) { nvenc_print_driver_requirement(avctx, AV_LOG_ERROR); return ret; @@ -166,6 +169,43 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) return 0; } +static int nvenc_push_context(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; + CUresult cu_res; + + if (ctx->d3d11_device) + return 0; + + cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); + if (cu_res != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int nvenc_pop_context(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; + CUresult cu_res; + CUcontext dummy; + + if (ctx->d3d11_device) + return 0; + + cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); + if (cu_res != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + static av_cold int nvenc_open_session(AVCodecContext *avctx) { NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0 }; @@ -175,8 +215,13 @@ static av_cold int nvenc_open_session(AVCodecContext *avctx) params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER; params.apiVersion = NVENCAPI_VERSION; - params.device = ctx->cu_context; - params.deviceType = NV_ENC_DEVICE_TYPE_CUDA; + if (ctx->d3d11_device) { + params.device = ctx->d3d11_device; + params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX; + } else { + params.device = ctx->cu_context; + params.deviceType = NV_ENC_DEVICE_TYPE_CUDA; + } ret = p_nvenc->nvEncOpenEncodeSessionEx(¶ms, &ctx->nvencoder); if (ret != NV_ENC_SUCCESS) { @@ -335,7 +380,6 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) int major, minor, ret; CUresult cu_res; CUdevice cu_device; - CUcontext dummy; int loglevel = AV_LOG_VERBOSE; if (ctx->device == LIST_DEVICES) @@ -378,11 +422,8 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) ctx->cu_context = ctx->cu_context_internal; - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_FATAL, "Failed popping CUDA context: 0x%x\n", (int)cu_res); + if ((ret = nvenc_pop_context(avctx)) < 0) goto fail2; - } if ((ret = nvenc_open_session(avctx)) < 0) goto fail2; @@ -398,20 +439,14 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) return 0; fail3: - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + if ((ret = nvenc_push_context(avctx)) < 0) + return ret; p_nvenc->nvEncDestroyEncoder(ctx->nvencoder); ctx->nvencoder = NULL; - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + if ((ret = nvenc_pop_context(avctx)) < 0) + return ret; fail2: dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal); @@ -437,23 +472,48 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) return AVERROR_BUG; } - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->hw_frames_ctx || avctx->hw_device_ctx) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11 || avctx->hw_frames_ctx || avctx->hw_device_ctx) { AVHWFramesContext *frames_ctx; AVHWDeviceContext *hwdev_ctx; - AVCUDADeviceContext *device_hwctx; + AVCUDADeviceContext *cuda_device_hwctx = NULL; +#if CONFIG_D3D11VA + AVD3D11VADeviceContext *d3d11_device_hwctx = NULL; +#endif int ret; if (avctx->hw_frames_ctx) { frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - device_hwctx = frames_ctx->device_ctx->hwctx; + if (frames_ctx->format == AV_PIX_FMT_CUDA) + cuda_device_hwctx = frames_ctx->device_ctx->hwctx; +#if CONFIG_D3D11VA + else if (frames_ctx->format == AV_PIX_FMT_D3D11) + d3d11_device_hwctx = frames_ctx->device_ctx->hwctx; +#endif + else + return AVERROR(EINVAL); } else if (avctx->hw_device_ctx) { hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; - device_hwctx = hwdev_ctx->hwctx; + if (hwdev_ctx->type == AV_HWDEVICE_TYPE_CUDA) + cuda_device_hwctx = hwdev_ctx->hwctx; +#if CONFIG_D3D11VA + else if (hwdev_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) + d3d11_device_hwctx = hwdev_ctx->hwctx; +#endif + else + return AVERROR(EINVAL); } else { return AVERROR(EINVAL); } - ctx->cu_context = device_hwctx->cuda_ctx; + if (cuda_device_hwctx) { + ctx->cu_context = cuda_device_hwctx->cuda_ctx; + } +#if CONFIG_D3D11VA + else if (d3d11_device_hwctx) { + ctx->d3d11_device = d3d11_device_hwctx->device; + ID3D11Device_AddRef(ctx->d3d11_device); + } +#endif ret = nvenc_open_session(avctx); if (ret < 0) @@ -1031,8 +1091,6 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) NV_ENC_PRESET_CONFIG preset_config = { 0 }; NVENCSTATUS nv_status = NV_ENC_SUCCESS; AVCPBProperties *cpb_props; - CUresult cu_res; - CUcontext dummy; int res = 0; int dw, dh; @@ -1123,19 +1181,15 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) if (res) return res; - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; nv_status = p_nvenc->nvEncInitializeEncoder(ctx->nvencoder, &ctx->init_encode_params); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_pop_context(avctx); + if (res < 0) + return res; if (nv_status != NV_ENC_SUCCESS) { return nvenc_print_error(avctx, nv_status, "InitializeEncoder failed"); @@ -1190,7 +1244,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 }; allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { ctx->surfaces[idx].in_ref = av_frame_alloc(); if (!ctx->surfaces[idx].in_ref) return AVERROR(ENOMEM); @@ -1222,7 +1276,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) nv_status = p_nvenc->nvEncCreateBitstreamBuffer(ctx->nvencoder, &allocOut); if (nv_status != NV_ENC_SUCCESS) { int err = nvenc_print_error(avctx, nv_status, "CreateBitstreamBuffer failed"); - if (avctx->pix_fmt != AV_PIX_FMT_CUDA) + if (avctx->pix_fmt != AV_PIX_FMT_CUDA && avctx->pix_fmt != AV_PIX_FMT_D3D11) p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[idx].input_surface); av_frame_free(&ctx->surfaces[idx].in_ref); return err; @@ -1239,10 +1293,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; - NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; - CUresult cu_res; - CUcontext dummy; - int i, res; + int i, res = 0, res2; ctx->surfaces = av_mallocz_array(ctx->nb_surfaces, sizeof(*ctx->surfaces)); if (!ctx->surfaces) @@ -1263,31 +1314,21 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx) if (!ctx->output_surface_ready_queue) return AVERROR(ENOMEM); - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; for (i = 0; i < ctx->nb_surfaces; i++) { if ((res = nvenc_alloc_surface(avctx, i)) < 0) - { - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } - return res; - } + goto fail; } - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } +fail: + res2 = nvenc_pop_context(avctx); + if (res2 < 0) + return res2; - return 0; + return res; } static av_cold int nvenc_setup_extradata(AVCodecContext *avctx) @@ -1328,20 +1369,16 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; - CUresult cu_res; - CUcontext dummy; - int i; + int i, res; /* the encoder has to be flushed before it can be closed */ if (ctx->nvencoder) { NV_ENC_PIC_PARAMS params = { .version = NV_ENC_PIC_PARAMS_VER, .encodePicFlags = NV_ENC_PIC_FLAG_EOS }; - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; p_nvenc->nvEncEncodePicture(ctx->nvencoder, ¶ms); } @@ -1351,7 +1388,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) av_fifo_freep(&ctx->output_surface_queue); av_fifo_freep(&ctx->unused_surface_queue); - if (ctx->surfaces && avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (ctx->surfaces && (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11)) { for (i = 0; i < ctx->nb_surfaces; ++i) { if (ctx->surfaces[i].input_surface) { p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->surfaces[i].in_map.mappedResource); @@ -1366,7 +1403,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) if (ctx->surfaces) { for (i = 0; i < ctx->nb_surfaces; ++i) { - if (avctx->pix_fmt != AV_PIX_FMT_CUDA) + if (avctx->pix_fmt != AV_PIX_FMT_CUDA && avctx->pix_fmt != AV_PIX_FMT_D3D11) p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[i].input_surface); av_frame_free(&ctx->surfaces[i].in_ref); p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->surfaces[i].output_surface); @@ -1378,11 +1415,9 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) if (ctx->nvencoder) { p_nvenc->nvEncDestroyEncoder(ctx->nvencoder); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_pop_context(avctx); + if (res < 0) + return res; } ctx->nvencoder = NULL; @@ -1390,6 +1425,13 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal); ctx->cu_context = ctx->cu_context_internal = NULL; +#if CONFIG_D3D11VA + if (ctx->d3d11_device) { + ID3D11Device_Release(ctx->d3d11_device); + ctx->d3d11_device = NULL; + } +#endif + nvenc_free_functions(&dl_fn->nvenc_dl); cuda_free_functions(&dl_fn->cuda_dl); @@ -1405,7 +1447,7 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) NvencContext *ctx = avctx->priv_data; int ret; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { AVHWFramesContext *frames_ctx; if (!avctx->hw_frames_ctx) { av_log(avctx, AV_LOG_ERROR, @@ -1413,6 +1455,11 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->format != avctx->pix_fmt) { + av_log(avctx, AV_LOG_ERROR, + "hw_frames_ctx must match the GPU frame type\n"); + return AVERROR(EINVAL); + } ctx->data_pix_fmt = frames_ctx->sw_format; } else { ctx->data_pix_fmt = avctx->pix_fmt; @@ -1518,7 +1565,9 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) int i, idx, ret; for (i = 0; i < ctx->nb_registered_frames; i++) { - if (ctx->registered_frames[i].ptr == (CUdeviceptr)frame->data[0]) + if (avctx->pix_fmt == AV_PIX_FMT_CUDA && ctx->registered_frames[i].ptr == frame->data[0]) + return i; + else if (avctx->pix_fmt == AV_PIX_FMT_D3D11 && ctx->registered_frames[i].ptr == frame->data[0] && ctx->registered_frames[i].ptr_index == (intptr_t)frame->data[1]) return i; } @@ -1527,12 +1576,19 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) return idx; reg.version = NV_ENC_REGISTER_RESOURCE_VER; - reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; reg.width = frames_ctx->width; reg.height = frames_ctx->height; reg.pitch = frame->linesize[0]; reg.resourceToRegister = frame->data[0]; + if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; + } + else if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { + reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX; + reg.subResourceIndex = (intptr_t)frame->data[1]; + } + reg.bufferFormat = nvenc_map_buffer_format(frames_ctx->sw_format); if (reg.bufferFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED) { av_log(avctx, AV_LOG_FATAL, "Invalid input pixel format: %s\n", @@ -1546,8 +1602,9 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) return AVERROR_UNKNOWN; } - ctx->registered_frames[idx].ptr = (CUdeviceptr)frame->data[0]; - ctx->registered_frames[idx].regptr = reg.registeredResource; + ctx->registered_frames[idx].ptr = frame->data[0]; + ctx->registered_frames[idx].ptr_index = reg.subResourceIndex; + ctx->registered_frames[idx].regptr = reg.registeredResource; return idx; } @@ -1561,10 +1618,10 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, int res; NVENCSTATUS nv_status; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { int reg_idx = nvenc_register_frame(avctx, frame); if (reg_idx < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not register an input CUDA frame\n"); + av_log(avctx, AV_LOG_ERROR, "Could not register an input HW frame\n"); return reg_idx; } @@ -1706,8 +1763,10 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur } slice_offsets = av_mallocz(slice_mode_data * sizeof(*slice_offsets)); - if (!slice_offsets) + if (!slice_offsets) { + res = AVERROR(ENOMEM); goto error; + } lock_params.version = NV_ENC_LOCK_BITSTREAM_VER; @@ -1733,7 +1792,7 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur nvenc_print_error(avctx, nv_status, "Failed unlocking bitstream buffer, expect the gates of mordor to open"); - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, tmpoutsurf->in_map.mappedResource); av_frame_unref(tmpoutsurf->in_ref); ctx->registered_frames[tmpoutsurf->reg_idx].mapped = 0; @@ -1810,10 +1869,8 @@ static int output_ready(AVCodecContext *avctx, int flush) int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) { NVENCSTATUS nv_status; - CUresult cu_res; - CUcontext dummy; NvencSurface *tmp_out_surf, *in_surf; - int res; + int res, res2; NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; @@ -1822,7 +1879,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) NV_ENC_PIC_PARAMS pic_params = { 0 }; pic_params.version = NV_ENC_PIC_PARAMS_VER; - if (!ctx->cu_context || !ctx->nvencoder) + if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); if (ctx->encoder_flushing) @@ -1833,19 +1890,15 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) if (!in_surf) return AVERROR(EAGAIN); - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; res = nvenc_upload_frame(avctx, frame, in_surf); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res2 = nvenc_pop_context(avctx); + if (res2 < 0) + return res2; if (res) return res; @@ -1881,19 +1934,15 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) ctx->encoder_flushing = 1; } - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_pop_context(avctx); + if (res < 0) + return res; if (nv_status != NV_ENC_SUCCESS && nv_status != NV_ENC_ERR_NEED_MORE_INPUT) @@ -1922,33 +1971,26 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt) { - CUresult cu_res; - CUcontext dummy; NvencSurface *tmp_out_surf; - int res; + int res, res2; NvencContext *ctx = avctx->priv_data; - NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; - if (!ctx->cu_context || !ctx->nvencoder) + if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); if (output_ready(avctx, ctx->encoder_flushing)) { av_fifo_generic_read(ctx->output_surface_ready_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL); - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; res = process_output_surface(avctx, pkt, tmp_out_surf); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res2 = nvenc_pop_context(avctx); + if (res2 < 0) + return res2; if (res) return res; diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index afb93cc22..2e51f1e94 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -19,10 +19,17 @@ #ifndef AVCODEC_NVENC_H #define AVCODEC_NVENC_H -#include "compat/nvenc/nvEncodeAPI.h" - #include "config.h" +#if CONFIG_D3D11VA +#define COBJMACROS +#include "libavutil/hwcontext_d3d11va.h" +#else +typedef void ID3D11Device; +#endif + +#include "compat/nvenc/nvEncodeAPI.h" + #include "compat/cuda/dynlink_loader.h" #include "libavutil/fifo.h" #include "libavutil/opt.h" @@ -107,6 +114,7 @@ typedef struct NvencContext NV_ENC_CONFIG encode_config; CUcontext cu_context; CUcontext cu_context_internal; + ID3D11Device *d3d11_device; int nb_surfaces; NvencSurface *surfaces; @@ -119,7 +127,8 @@ typedef struct NvencContext int encoder_flushing; struct { - CUdeviceptr ptr; + void *ptr; + int ptr_index; NV_ENC_REGISTERED_PTR regptr; int mapped; } registered_frames[MAX_REGISTERED_FRAMES]; diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index c3b4bac74..bc7bbcdde 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -171,9 +171,10 @@ AVCodec ff_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .priv_class = &nvenc_class, .defaults = defaults, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = ff_nvenc_pix_fmts, + .wrapper_name = "nvenc", }; #endif @@ -199,9 +200,10 @@ AVCodec ff_nvenc_h264_encoder = { .priv_data_size = sizeof(NvencContext), .priv_class = &nvenc_h264_class, .defaults = defaults, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = ff_nvenc_pix_fmts, + .wrapper_name = "nvenc", }; #endif @@ -227,7 +229,8 @@ AVCodec ff_h264_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .priv_class = &h264_nvenc_class, .defaults = defaults, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = ff_nvenc_pix_fmts, + .wrapper_name = "nvenc", }; diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c index 89e8c3e53..0df7eab8c 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -161,8 +161,9 @@ AVCodec ff_nvenc_hevc_encoder = { .priv_class = &nvenc_hevc_class, .defaults = defaults, .pix_fmts = ff_nvenc_pix_fmts, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "nvenc", }; #endif @@ -188,6 +189,7 @@ AVCodec ff_hevc_nvenc_encoder = { .priv_class = &hevc_nvenc_class, .defaults = defaults, .pix_fmts = ff_nvenc_pix_fmts, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "nvenc", }; diff --git a/libavcodec/options.c b/libavcodec/options.c index 82e12179a..41b60521c 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -30,7 +30,6 @@ #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/opt.h" -#include /* FLT_MIN, FLT_MAX */ #include FF_DISABLE_DEPRECATION_WARNINGS diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 2ac37c3ff..d89f58d54 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -54,26 +54,11 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_GMC -{"gmc", "use gmc", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_GMC }, INT_MIN, INT_MAX, V|E, "flags"}, -#endif -#if FF_API_MV0 -{"mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_MV0 }, INT_MIN, INT_MAX, V|E, "flags"}, -#endif -#if FF_API_INPUT_PRESERVED -{"input_preserved", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_INPUT_PRESERVED }, INT_MIN, INT_MAX, 0, "flags"}, -#endif {"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"}, -#if FF_API_EMU_EDGE -{"emu_edge", "do not draw edges", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_EMU_EDGE }, INT_MIN, INT_MAX, 0, "flags"}, -#endif {"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"}, -#if FF_API_NORMALIZE_AQP -{"naq", "normalize adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_NORMALIZE_AQP }, INT_MIN, INT_MAX, V|E, "flags"}, -#endif {"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"}, @@ -91,21 +76,6 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_MOTION_EST -{"me_method", "set motion estimation method", OFFSET(me_method), AV_OPT_TYPE_INT, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method"}, -{"zero", "zero motion estimation (fastest)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ZERO }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"full", "full motion estimation (slowest)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_FULL }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"epzs", "EPZS motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"esa", "esa motion estimation (alias for full)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_FULL }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"tesa", "tesa motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_TESA }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"dia", "diamond motion estimation (alias for EPZS)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"log", "log motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_LOG }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"phods", "phods motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_PHODS }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"x1", "X1 motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_X1 }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"hex", "hex motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_HEX }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"umh", "umh motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_UMH }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"iter", "iter motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ITER }, INT_MIN, INT_MAX, V|E, "me_method" }, -#endif {"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}, @@ -123,9 +93,6 @@ static const AVOption avcodec_options[] = { {"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_RC_STRATEGY -{"rc_strategy", "ratecontrol method", OFFSET(rc_strategy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif #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}, @@ -144,16 +111,10 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_OLD_MSMPEG4 -{"old_msmpeg4", "some old lavc-generated MSMPEG4v3 files (no autodetection)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_OLD_MSMPEG4 }, INT_MIN, INT_MAX, V|D, "bug"}, -#endif {"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"}, -#if FF_API_AC_VLC -{"ac_vlc", "illegal VLC bug (autodetected per FOURCC)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_AC_VLC }, INT_MIN, INT_MAX, V|D, "bug"}, -#endif {"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"}, @@ -185,27 +146,13 @@ static const AVOption avcodec_options[] = { #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 -#if FF_API_MPV_OPT -{"qsquish", "deprecated, use encoder private options instead", OFFSET(rc_qsquish), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, 0, 99, V|E}, -{"rc_qmod_amp", "deprecated, use encoder private options instead", OFFSET(rc_qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, -FLT_MAX, FLT_MAX, V|E}, -{"rc_qmod_freq", "deprecated, use encoder private options instead", OFFSET(rc_qmod_freq), 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}, -#if FF_API_MPV_OPT -{"rc_eq", "deprecated, use encoder private options instead", OFFSET(rc_eq), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, V|E}, -#endif {"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}, -#if FF_API_MPV_OPT -{"rc_buf_aggressivity", "deprecated, use encoder private options instead", OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, V|E}, -#endif {"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}, -#if FF_API_MPV_OPT -{"rc_init_cplx", "deprecated, use encoder private options instead", OFFSET(rc_initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, -FLT_MAX, FLT_MAX, V|E}, -#endif {"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"}, @@ -225,19 +172,10 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_ARCH_SH4 -{"sh4", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SH4 }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif {"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"}, -#if FF_API_ARCH_ALPHA -{"simplealpha", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEALPHA }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif -#if FF_API_UNUSED_MEMBERS -{"ipp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_IPP }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif /* FF_API_UNUSED_MEMBERS */ {"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"}, @@ -269,9 +207,6 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_UNUSED_MEMBERS -{"pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_PTS }, INT_MIN, INT_MAX, V|D, "debug"}, -#endif /* FF_API_UNUSED_MEMBERS */ {"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"}, @@ -282,12 +217,6 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_VISMV -{"vismv", "visualize motion vectors (MVs) (deprecated)", OFFSET(debug_mv), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, V|D, "debug_mv"}, -{"pf", "forward predicted MVs of P-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_P_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"}, -{"bf", "forward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"}, -{"bb", "backward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_BACK }, INT_MIN, INT_MAX, V|D, "debug_mv"}, -#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"}, @@ -318,14 +247,7 @@ static const AVOption avcodec_options[] = { {"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"}, {"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}, -#if FF_API_AFD -{"dtg_active_format", NULL, OFFSET(dtg_active_format), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#endif {"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}, -#if FF_API_QUANT_BIAS -{"ibias", "intra quant bias", OFFSET(intra_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, V|E}, -{"pbias", "inter quant bias", OFFSET(inter_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, V|E}, -#endif {"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"}, @@ -333,45 +255,25 @@ static const AVOption avcodec_options[] = { {"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"}, -#if FF_API_UNUSED_MEMBERS -{"deflate", "deflate-based coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_DEFLATE }, INT_MIN, INT_MAX, V|E, "coder"}, -#endif /* FF_API_UNUSED_MEMBERS */ #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}, -#if FF_API_XVMC -{"xvmc_acceleration", NULL, OFFSET(xvmc_acceleration), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#endif /* FF_API_XVMC */ {"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_STREAM_CODEC_TAG -{"stream_codec_tag", NULL, OFFSET(stream_codec_tag), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#endif #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_MPV_OPT -{"lmin", "deprecated, use encoder private options instead", OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E}, -{"lmax", "deprecated, use encoder private options instead", OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 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}, {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, -#if FF_API_ERROR_RATE -{"error", NULL, OFFSET(error_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif {"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"}, -#if FF_API_MPV_OPT -{"me_threshold", "motion estimation threshold", OFFSET(me_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -{"mb_threshold", "macroblock threshold", OFFSET(mb_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif {"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}, @@ -407,9 +309,6 @@ static const AVOption avcodec_options[] = { {"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 -#if FF_API_MPV_OPT -{"border_mask", "deprecated, use encoder private options instead", OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, -FLT_MAX, FLT_MAX, V|E}, -#endif {"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 @@ -435,9 +334,6 @@ static const AVOption avcodec_options[] = { {"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}, -#if FF_API_UNUSED_MEMBERS -{"sc_factor", "multiplied by qscale for each frame and added to scene_change_score", OFFSET(scenechange_factor), AV_OPT_TYPE_INT, {.i64 = 6 }, 0, INT_MAX, V|E}, -#endif /* FF_API_UNUSED_MEMBERS */ {"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}, diff --git a/libavcodec/opus.c b/libavcodec/opus.c index 5847e88e1..aa827b604 100644 --- a/libavcodec/opus.c +++ b/libavcodec/opus.c @@ -29,7 +29,8 @@ #include "libavutil/error.h" #include "libavutil/ffmath.h" -#include "opus.h" +#include "opus_celt.h" +#include "opustab.h" #include "vorbis.h" static const uint16_t opus_frame_duration[32] = { @@ -438,3 +439,459 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, 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/libavcodec/opus.h b/libavcodec/opus.h index c3cbaec35..edbaab5ce 100644 --- a/libavcodec/opus.h +++ b/libavcodec/opus.h @@ -150,7 +150,9 @@ typedef struct ChannelMap { } ChannelMap; typedef struct OpusContext { + AVClass *av_class; OpusStreamContext *streams; + int apply_phase_inv; /* current output buffers for each streams */ float **out; @@ -189,4 +191,10 @@ int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc, 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/libavcodec/opus_celt.c b/libavcodec/opus_celt.c index 84d484753..115dd8c63 100644 --- a/libavcodec/opus_celt.c +++ b/libavcodec/opus_celt.c @@ -143,345 +143,14 @@ static void celt_decode_tf_changes(CeltFrame *f, OpusRangeCoder *rc) } } -static void celt_decode_allocation(CeltFrame *f, OpusRangeCoder *rc) -{ - // approx. maximum bit allocation for each band before boost/trim - int cap[CELT_MAX_BANDS]; - int boost[CELT_MAX_BANDS]; - int threshold[CELT_MAX_BANDS]; - int bits1[CELT_MAX_BANDS]; - int bits2[CELT_MAX_BANDS]; - int trim_offset[CELT_MAX_BANDS]; - - int skip_start_band = f->start_band; - int dynalloc = 6; - int alloctrim = 5; - int extrabits = 0; - - int skip_bit = 0; - int intensity_stereo_bit = 0; - int dual_stereo_bit = 0; - - int remaining, bandbits; - int low, high, total, done; - int totalbits; - int consumed; - int i, j; - - consumed = opus_rc_tell(rc); - - /* obtain spread flag */ - f->spread = CELT_SPREAD_NORMAL; - if (consumed + 4 <= f->framebits) - f->spread = ff_opus_rc_dec_cdf(rc, ff_celt_model_spread); - - /* generate static allocation caps */ - for (i = 0; i < CELT_MAX_BANDS; i++) { - cap[i] = (ff_celt_static_caps[f->size][f->channels - 1][i] + 64) - * ff_celt_freq_range[i] << (f->channels - 1) << f->size >> 2; - } - - /* obtain band boost */ - totalbits = f->framebits << 3; // convert to 1/8 bits - consumed = opus_rc_tell_frac(rc); - for (i = f->start_band; i < f->end_band; i++) { - int quanta, band_dynalloc; - - boost[i] = 0; - - quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size; - quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta)); - band_dynalloc = dynalloc; - while (consumed + (band_dynalloc<<3) < totalbits && boost[i] < cap[i]) { - int add = ff_opus_rc_dec_log(rc, band_dynalloc); - consumed = opus_rc_tell_frac(rc); - if (!add) - break; - - boost[i] += quanta; - totalbits -= quanta; - band_dynalloc = 1; - } - /* dynalloc is more likely to occur if it's already been used for earlier bands */ - if (boost[i]) - dynalloc = FFMAX(2, dynalloc - 1); - } - - /* obtain allocation trim */ - if (consumed + (6 << 3) <= totalbits) - alloctrim = ff_opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim); - - /* anti-collapse bit reservation */ - totalbits = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1; - f->anticollapse_needed = 0; - if (f->blocks > 1 && f->size >= 2 && - totalbits >= ((f->size + 2) << 3)) - f->anticollapse_needed = 1 << 3; - totalbits -= f->anticollapse_needed; - - /* band skip bit reservation */ - if (totalbits >= 1 << 3) - skip_bit = 1 << 3; - totalbits -= skip_bit; - - /* intensity/dual stereo bit reservation */ - if (f->channels == 2) { - intensity_stereo_bit = ff_celt_log2_frac[f->end_band - f->start_band]; - if (intensity_stereo_bit <= totalbits) { - totalbits -= intensity_stereo_bit; - if (totalbits >= 1 << 3) { - dual_stereo_bit = 1 << 3; - totalbits -= 1 << 3; - } - } else - intensity_stereo_bit = 0; - } - - for (i = f->start_band; i < f->end_band; i++) { - int trim = alloctrim - 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 = ff_celt_freq_range[i] * ff_celt_static_alloc[center][i] - << (f->channels - 1) << f->size >> 2; - - if (bandbits) - bandbits = FFMAX(0, bandbits + trim_offset[i]); - bandbits += boost[i]; - - if (bandbits >= threshold[i] || done) { - done = 1; - total += FFMIN(bandbits, cap[i]); - } else if (bandbits >= f->channels << 3) - total += f->channels << 3; - } - - if (total > totalbits) - high = center - 1; - else - low = center + 1; - } - high = low--; - - for (i = f->start_band; i < f->end_band; i++) { - bits1[i] = ff_celt_freq_range[i] * ff_celt_static_alloc[low][i] - << (f->channels - 1) << f->size >> 2; - bits2[i] = high >= CELT_VECTORS ? cap[i] : - ff_celt_freq_range[i] * ff_celt_static_alloc[high][i] - << (f->channels - 1) << f->size >> 2; - - if (bits1[i]) - bits1[i] = FFMAX(0, bits1[i] + trim_offset[i]); - if (bits2[i]) - bits2[i] = FFMAX(0, bits2[i] + trim_offset[i]); - if (low) - bits1[i] += boost[i]; - bits2[i] += boost[i]; - - if (boost[i]) - skip_start_band = i; - bits2[i] = FFMAX(0, bits2[i] - bits1[i]); - } - - /* 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, cap[j]); - } else if (bandbits >= f->channels << 3) - total += f->channels << 3; - } - if (total > totalbits) - high = center; - else - low = center; - } - - 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, cap[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_start_band) { - /* all remaining bands are not skipped */ - totalbits += skip_bit; - break; - } - - /* determine the number of bits available for coding "do not skip" markers */ - remaining = totalbits - 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] - + FFMAX(0, remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band])); - - /* 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 )) { - if (ff_opus_rc_dec_log(rc, 1)) - break; - - total += 1 << 3; - allocation -= 1 << 3; - } - - /* the band is skipped, so reclaim its bits */ - total -= f->pulses[j]; - if (intensity_stereo_bit) { - total -= intensity_stereo_bit; - intensity_stereo_bit = ff_celt_log2_frac[j - f->start_band]; - total += intensity_stereo_bit; - } - - total += f->pulses[j] = (allocation >= f->channels << 3) ? - f->channels << 3 : 0; - } - - /* obtain stereo flags */ - f->intensity_stereo = 0; - f->dual_stereo = 0; - if (intensity_stereo_bit) - f->intensity_stereo = f->start_band + - ff_opus_rc_dec_uint(rc, f->coded_bands + 1 - f->start_band); - if (f->intensity_stereo <= f->start_band) - totalbits += dual_stereo_bit; /* no intensity stereo means no dual stereo */ - else if (dual_stereo_bit) - f->dual_stereo = ff_opus_rc_dec_log(rc, 1); - - /* supply the remaining bits in this frame to lower bands */ - remaining = totalbits - 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++) { - int bits = FFMIN(remaining, ff_celt_freq_range[i]); - - f->pulses[i] += bits + bandbits * ff_celt_freq_range[i]; - remaining -= bits; - } - - 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 offset; // fine energy quantization offset, i.e. - // extra bits assigned over the standard - // totalbits/dof - int fine_bits, max_bits; - - extrabits = FFMAX(0, f->pulses[i] - cap[i]); - 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(0, f->pulses[i] - (f->channels << 3)); - 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; - } -} - 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 norm = exp2f(block->energy[i] + ff_celt_mean_energy[i]); + 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; @@ -675,98 +344,6 @@ static void process_anticollapse(CeltFrame *f, CeltBlock *block, float *X) } } -static void celt_decode_bands(CeltFrame *f, OpusRangeCoder *rc) -{ - float lowband_scratch[8 * 22]; - float norm[2 * 8 * 100]; - - int totalbits = (f->framebits << 3) - f->anticollapse_needed; - - int update_lowband = 1; - int lowband_offset = 0; - - int i, j; - - memset(f->block[0].coeffs, 0, sizeof(f->block[0].coeffs)); - memset(f->block[1].coeffs, 0, sizeof(f->block[0].coeffs)); - - 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; - - int consumed = opus_rc_tell_frac(rc); - float *norm2 = norm + 8 * 100; - 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] && - (update_lowband || lowband_offset == 0)) - lowband_offset = i; - - /* 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 (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++) - norm[j] = (norm[j] + norm2[j]) / 2; - } - - if (f->dual_stereo) { - cm[0] = f->pvq->decode_band(f->pvq, f, rc, i, X, NULL, band_size, b / 2, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + band_offset, 0, 1.0f, lowband_scratch, cm[0]); - - cm[1] = f->pvq->decode_band(f->pvq, f, rc, i, Y, NULL, band_size, b/2, f->blocks, - effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL, f->size, - norm2 + band_offset, 0, 1.0f, lowband_scratch, cm[1]); - } else { - cm[0] = f->pvq->decode_band(f->pvq, f, rc, i, X, Y, band_size, b, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + 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); - } -} - int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, float **output, int channels, int frame_size, int start_band, int end_band) @@ -806,8 +383,10 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, if (!f->output_channels) f->output_channels = channels; - memset(f->block[0].collapse_masks, 0, sizeof(f->block[0].collapse_masks)); - memset(f->block[1].collapse_masks, 0, sizeof(f->block[1].collapse_masks)); + 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); @@ -842,9 +421,9 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, celt_decode_coarse_energy(f, rc); celt_decode_tf_changes (f, rc); - celt_decode_allocation (f, rc); + ff_celt_bitalloc (f, rc, 0); celt_decode_fine_energy (f, rc); - celt_decode_bands (f, rc); + ff_celt_quant_bands (f, rc); if (f->anticollapse_needed) f->anticollapse = ff_opus_rc_get_raw(rc, 1); @@ -984,7 +563,8 @@ void ff_celt_free(CeltFrame **f) av_freep(f); } -int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels) +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv) { CeltFrame *frm; int i, ret; @@ -1001,12 +581,13 @@ int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels) 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) + if ((ret = ff_celt_pvq_init(&frm->pvq, 0)) < 0) goto fail; frm->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); diff --git a/libavcodec/opus_celt.h b/libavcodec/opus_celt.h index 45d50ab27..9289a1867 100644 --- a/libavcodec/opus_celt.h +++ b/libavcodec/opus_celt.h @@ -98,6 +98,7 @@ struct CeltFrame { CeltPVQ *pvq; int channels; int output_channels; + int apply_phase_inv; enum CeltBlockSize size; int start_band; @@ -156,7 +157,8 @@ static av_always_inline void celt_renormalize_vector(float *X, int N, float gain X[i] *= g; } -int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels); +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv); void ff_celt_free(CeltFrame **f); diff --git a/libavcodec/opus_parser.c b/libavcodec/opus_parser.c index 893573eb8..28b093390 100644 --- a/libavcodec/opus_parser.c +++ b/libavcodec/opus_parser.c @@ -43,6 +43,7 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le const uint8_t *buf = start + 1; int start_trim_flag, end_trim_flag, control_extension_flag, control_extension_length; uint8_t flags; + uint64_t payload_len_tmp; GetByteContext gb; bytestream2_init(&gb, buf, buf_len); @@ -52,11 +53,11 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le end_trim_flag = (flags >> 3) & 1; control_extension_flag = (flags >> 2) & 1; - *payload_len = 0; + payload_len_tmp = *payload_len = 0; while (bytestream2_peek_byte(&gb) == 0xff) - *payload_len += bytestream2_get_byte(&gb); + payload_len_tmp += bytestream2_get_byte(&gb); - *payload_len += bytestream2_get_byte(&gb); + payload_len_tmp += bytestream2_get_byte(&gb); if (start_trim_flag) bytestream2_skip(&gb, 2); @@ -67,6 +68,11 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le bytestream2_skip(&gb, control_extension_length); } + if (bytestream2_tell(&gb) + payload_len_tmp > buf_len) + return NULL; + + *payload_len = payload_len_tmp; + return buf + bytestream2_tell(&gb); } @@ -104,6 +110,10 @@ static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx, state = (state << 8) | payload[i]; if ((state & OPUS_TS_MASK) == OPUS_TS_HEADER) { payload = parse_opus_ts_header(payload, &payload_len, buf_size - i); + if (!payload) { + av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg TS header.\n"); + return AVERROR_INVALIDDATA; + } *header_len = payload - buf; start_found = 1; break; diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c index f98b85d36..0dbf14184 100644 --- a/libavcodec/opus_pvq.c +++ b/libavcodec/opus_pvq.c @@ -486,8 +486,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, int duration, float *lowband_out, int level, float gain, float *lowband_scratch, - int fill, int quant, - QUANT_FN(*rec)) + int fill, int quant) { int i; const uint8_t *cache; @@ -643,6 +642,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, } } 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; } @@ -699,8 +699,8 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, 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 = rec(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration, - lowband_out, level, gain, lowband_scratch, orig_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]; @@ -752,24 +752,25 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, 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 = rec(pvq, f, rc, band, X, NULL, N, mbits, blocks, lowband, - duration, next_lowband_out1, next_level, - stereo ? 1.0f : (gain * mid), lowband_scratch, fill); + 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 = rec(pvq, f, rc, band, Y, NULL, N, sbits, blocks, next_lowband2, - duration, NULL, next_level, gain * side, NULL, - fill >> blocks); + 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 = rec(pvq, f, rc, band, Y, NULL, N, sbits, blocks, next_lowband2, - duration, NULL, next_level, gain * side, NULL, fill >> blocks); + 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) @@ -777,9 +778,9 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, /* In stereo mode, we do not apply a scaling to the mid because * we need the normalized mid for folding later */ - cm |= rec(pvq, f, rc, band, X, NULL, N, mbits, blocks, lowband, duration, - next_lowband_out1, next_level, stereo ? 1.0f : (gain * mid), - lowband_scratch, fill); + 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 { @@ -873,80 +874,34 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, return cm; } - static QUANT_FN(pvq_decode_band) { +#if CONFIG_OPUS_DECODER return quant_band_template(pvq, f, rc, band, X, Y, N, b, blocks, lowband, duration, - lowband_out, level, gain, lowband_scratch, fill, 0, - pvq->decode_band); + lowband_out, level, gain, lowband_scratch, fill, 0); +#else + return 0; +#endif } static QUANT_FN(pvq_encode_band) { +#if CONFIG_OPUS_ENCODER return quant_band_template(pvq, f, rc, band, X, Y, N, b, blocks, lowband, duration, - lowband_out, level, gain, lowband_scratch, fill, 1, - pvq->encode_band); + lowband_out, level, gain, lowband_scratch, fill, 1); +#else + return 0; +#endif } -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->encode_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->encode_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->encode_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]); - 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; -} - -int av_cold ff_celt_pvq_init(CeltPVQ **pvq) +int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode) { CeltPVQ *s = av_malloc(sizeof(CeltPVQ)); if (!s) return AVERROR(ENOMEM); - s->pvq_search = ppp_pvq_search_c; - s->decode_band = pvq_decode_band; - s->encode_band = pvq_encode_band; - s->band_cost = pvq_band_cost; + s->pvq_search = ppp_pvq_search_c; + s->quant_band = encode ? pvq_encode_band : pvq_decode_band; if (ARCH_X86) ff_opus_dsp_init_x86(s); diff --git a/libavcodec/opus_pvq.h b/libavcodec/opus_pvq.h index 924633736..e2f01a01b 100644 --- a/libavcodec/opus_pvq.h +++ b/libavcodec/opus_pvq.h @@ -37,15 +37,12 @@ struct CeltPVQ { DECLARE_ALIGNED(32, float, hadamard_tmp)[256]; float (*pvq_search)(float *X, int *y, int K, int N); - - QUANT_FN(*decode_band); - QUANT_FN(*encode_band); - float (*band_cost)(struct CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, - int band, float *bits, float lambda); + QUANT_FN(*quant_band); }; -int ff_celt_pvq_init (struct CeltPVQ **pvq); void ff_opus_dsp_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/libavcodec/opus_silk.c b/libavcodec/opus_silk.c index 3c9c849c2..344333cc1 100644 --- a/libavcodec/opus_silk.c +++ b/libavcodec/opus_silk.c @@ -185,8 +185,15 @@ static inline int silk_is_lpc_stable(const int16_t lpc[16], int order) row = lpc32[k & 1]; for (j = 0; j < k; j++) { - int x = prevrow[j] - ROUND_MULL(prevrow[k - j - 1], rc, 31); - row[j] = ROUND_MULL(x, gain, fbits); + int x = av_sat_sub32(prevrow[j], ROUND_MULL(prevrow[k - j - 1], rc, 31)); + int64_t tmp = ROUND_MULL(x, gain, fbits); + + /* per RFC 8251 section 6, if this calculation overflows, the filter + is considered unstable. */ + if (tmp < INT32_MIN || tmp > INT32_MAX) + return 0; + + row[j] = (int32_t)tmp; } } } diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c index 5a7ba9dbb..03086dea9 100644 --- a/libavcodec/opusdec.c +++ b/libavcodec/opusdec.c @@ -687,7 +687,7 @@ static av_cold int opus_decode_init(AVCodecContext *avctx) if (ret < 0) goto fail; - ret = ff_celt_init(avctx, &s->celt, s->output_channels); + ret = ff_celt_init(avctx, &s->celt, s->output_channels, c->apply_phase_inv); if (ret < 0) goto fail; @@ -712,9 +712,24 @@ fail: return ret; } +#define OFFSET(x) offsetof(OpusContext, x) +#define AD AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption opus_options[] = { + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AD }, + { NULL }, +}; + +static const AVClass opus_class = { + .class_name = "Opus Decoder", + .item_name = av_default_item_name, + .option = opus_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_opus_decoder = { .name = "opus", .long_name = NULL_IF_CONFIG_SMALL("Opus"), + .priv_class = &opus_class, .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_OPUS, .priv_data_size = sizeof(OpusContext), diff --git a/libavcodec/opusenc.c b/libavcodec/opusenc.c index 79d20dc6e..4068c4359 100644 --- a/libavcodec/opusenc.c +++ b/libavcodec/opusenc.c @@ -255,7 +255,7 @@ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) } } -static void celt_enc_tf(OpusRangeCoder *rc, CeltFrame *f) +static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc) { int i, tf_select = 0, diff = 0, tf_changed = 0, tf_select_needed; int bits = f->transient ? 2 : 4; @@ -282,333 +282,6 @@ static void celt_enc_tf(OpusRangeCoder *rc, CeltFrame *f) f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]]; } -void ff_celt_enc_bitalloc(OpusRangeCoder *rc, CeltFrame *f) -{ - 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 *cap = f->caps; - int boost[CELT_MAX_BANDS]; - int trim_offset[CELT_MAX_BANDS]; - int threshold[CELT_MAX_BANDS]; - int bits1[CELT_MAX_BANDS]; - int bits2[CELT_MAX_BANDS]; - - /* Tell the spread to the decoder */ - if (opus_rc_tell(rc) + 4 <= f->framebits) - ff_opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread); - else - f->spread = CELT_SPREAD_NORMAL; - - /* Generate static allocation caps */ - for (i = 0; i < CELT_MAX_BANDS; i++) { - cap[i] = (ff_celt_static_caps[f->size][f->channels - 1][i] + 64) - * ff_celt_freq_range[i] << (f->channels - 1) << f->size >> 2; - } - - /* Band boosts */ - tbits_8ths = f->framebits << 3; - for (i = f->start_band; i < f->end_band; i++) { - int quanta, b_dynalloc, boost_amount = f->alloc_boost[i]; - - boost[i] = 0; - - quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size; - quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta)); - b_dynalloc = dynalloc; - - while (opus_rc_tell_frac(rc) + (b_dynalloc << 3) < tbits_8ths && boost[i] < cap[i]) { - int is_boost = boost_amount--; - - ff_opus_rc_enc_log(rc, is_boost, b_dynalloc); - if (!is_boost) - break; - - boost[i] += quanta; - tbits_8ths -= quanta; - - b_dynalloc = 1; - } - - if (boost[i]) - dynalloc = FFMAX(2, dynalloc - 1); - } - - /* Put allocation trim */ - if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths) - ff_opus_rc_enc_cdf(rc, f->alloc_trim, 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 = ff_celt_freq_range[i] * ff_celt_static_alloc[center][i] - << (f->channels - 1) << f->size >> 2; - - if (bandbits) - bandbits = FFMAX(0, bandbits + trim_offset[i]); - bandbits += boost[i]; - - if (bandbits >= threshold[i] || done) { - done = 1; - total += FFMIN(bandbits, cap[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] = ff_celt_freq_range[i] * ff_celt_static_alloc[low][i] - << (f->channels - 1) << f->size >> 2; - bits2[i] = high >= CELT_VECTORS ? cap[i] : - ff_celt_freq_range[i] * ff_celt_static_alloc[high][i] - << (f->channels - 1) << f->size >> 2; - - if (bits1[i]) - bits1[i] = FFMAX(0, bits1[i] + trim_offset[i]); - if (bits2[i]) - bits2[i] = FFMAX(0, bits2[i] + trim_offset[i]); - if (low) - bits1[i] += boost[i]; - bits2[i] += boost[i]; - - if (boost[i]) - skip_startband = i; - bits2[i] = FFMAX(0, bits2[i] - bits1[i]); - } - - /* 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, cap[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, cap[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] - + FFMAX(0, remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band])); - - /* 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)) { - const int do_not_skip = f->coded_bands <= f->skip_band_floor; - ff_opus_rc_enc_log(rc, do_not_skip, 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; - } - - /* Encode stereo flags */ - 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); - } - if (f->intensity_stereo <= f->start_band) - tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */ - else if (dualstereo_bit) - ff_opus_rc_enc_log(rc, f->dual_stereo, 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++) { - 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 offset; // fine energy quantization offset, i.e. - // extra bits assigned over the standard - // totalbits/dof - int fine_bits, max_bits; - - extrabits = FFMAX(0, f->pulses[i] - cap[i]); - 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(0, f->pulses[i] - (f->channels << 3)); - 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; - } -} - static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f) { float gain = f->pf_gain; @@ -690,7 +363,7 @@ static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, } } -static void celt_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, +static void celt_quant_coarse(CeltFrame *f, OpusRangeCoder *rc, float last_energy[][CELT_MAX_BANDS]) { uint32_t inter, intra; @@ -710,7 +383,7 @@ static void celt_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, } } -static void celt_quant_fine(OpusRangeCoder *rc, CeltFrame *f) +static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc) { int i, ch; for (i = f->start_band; i < f->end_band; i++) { @@ -747,95 +420,6 @@ static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f } } -static void celt_quant_bands(OpusRangeCoder *rc, CeltFrame *f) -{ - float lowband_scratch[8 * 22]; - float norm[2 * 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; - - int consumed = opus_rc_tell_frac(rc); - float *norm2 = norm + 8 * 100; - 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] && - (update_lowband || lowband_offset == 0)) - lowband_offset = i; - - /* 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 (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++) - norm[j] = (norm[j] + norm2[j]) / 2; - } - - if (f->dual_stereo) { - cm[0] = f->pvq->encode_band(f->pvq, f, rc, i, X, NULL, band_size, b / 2, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + band_offset, 0, 1.0f, lowband_scratch, cm[0]); - - cm[1] = f->pvq->encode_band(f->pvq, f, rc, i, Y, NULL, band_size, b / 2, f->blocks, - effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL, f->size, - norm2 + band_offset, 0, 1.0f, lowband_scratch, cm[1]); - } else { - cm[0] = f->pvq->encode_band(f->pvq, f, rc, i, X, Y, band_size, b, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + 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); - } -} - static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f, int index) { @@ -883,11 +467,11 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, ff_opus_rc_enc_log(rc, f->transient, 3); /* Main encoding */ - celt_quant_coarse(rc, f, s->last_quantized_energy); - celt_enc_tf (rc, f); - ff_celt_enc_bitalloc(rc, f); - celt_quant_fine (rc, f); - celt_quant_bands (rc, f); + 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) @@ -1080,7 +664,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) ff_af_queue_init(avctx, &s->afq); - if ((ret = ff_celt_pvq_init(&s->pvq)) < 0) + 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))) @@ -1117,6 +701,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) 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; } diff --git a/libavcodec/opusenc.h b/libavcodec/opusenc.h index 3273d0a9a..b9162ebec 100644 --- a/libavcodec/opusenc.h +++ b/libavcodec/opusenc.h @@ -51,6 +51,4 @@ typedef struct OpusPacketInfo { int frames; } OpusPacketInfo; -void ff_celt_enc_bitalloc(OpusRangeCoder *rc, CeltFrame *f); - #endif /* AVCODEC_OPUSENC_H */ diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c index b446d41f7..8aded2140 100644 --- a/libavcodec/opusenc_psy.c +++ b/libavcodec/opusenc_psy.c @@ -25,6 +25,56 @@ #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) { @@ -69,7 +119,7 @@ static void step_collect_psy_metrics(OpusPsyContext *s, int index) 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); + dist_dev += (avg_c_s - c_s)*(avg_c_s - c_s); } st->tone[ch][i] += sqrtf(dist_dev); @@ -316,11 +366,11 @@ static int bands_dist(OpusPsyContext *s, CeltFrame *f, float *total_dist) OpusRangeCoder dump; ff_opus_rc_enc_init(&dump); - ff_celt_enc_bitalloc(&dump, f); + ff_celt_bitalloc(f, &dump, 1); for (i = 0; i < CELT_MAX_BANDS; i++) { float bits = 0.0f; - float dist = f->pvq->band_cost(f->pvq, f, &dump, i, &bits, s->lambda); + float dist = pvq_band_cost(f->pvq, f, &dump, i, &bits, s->lambda); tdist += dist; } @@ -333,6 +383,10 @@ 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); @@ -346,6 +400,9 @@ static void celt_search_for_intensity(OpusPsyContext *s, CeltFrame *f) int i, best_band = CELT_MAX_BANDS - 1; float dist, best_dist = FLT_MAX; + if (s->avctx->channels < 2) + return; + /* TODO: fix, make some heuristic up here using the lambda value */ float end_band = 0; @@ -370,7 +427,6 @@ static int celt_search_for_tf(OpusPsyContext *s, OpusPsyStep **start, CeltFrame for (cway = 0; cway < 2; cway++) { int mag[2]; int base = f->transient ? 120 : 960; - int i; for (i = 0; i < 2; i++) { int c = ff_celt_tf_select[f->size][f->transient][cway][i]; diff --git a/libavcodec/parser.c b/libavcodec/parser.c index 670680ea7..747ea2ee8 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -25,9 +25,9 @@ #include #include "libavutil/avassert.h" -#include "libavutil/atomic.h" #include "libavutil/internal.h" #include "libavutil/mem.h" +#include "libavutil/thread.h" #include "internal.h" #include "parser.h" @@ -42,11 +42,14 @@ AVCodecParser *av_parser_next(const AVCodecParser *p) return av_first_parser; } +static AVMutex parser_register_mutex = AV_MUTEX_INITIALIZER; + void av_register_codec_parser(AVCodecParser *parser) { - do { - parser->next = av_first_parser; - } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser)); + ff_mutex_lock(&parser_register_mutex); + parser->next = av_first_parser; + av_first_parser = parser; + ff_mutex_unlock(&parser_register_mutex); } AVCodecParserContext *av_parser_init(int codec_id) diff --git a/libavcodec/pixlet.c b/libavcodec/pixlet.c index a9cfe085c..03a2cdacc 100644 --- a/libavcodec/pixlet.c +++ b/libavcodec/pixlet.c @@ -28,12 +28,14 @@ #include "avcodec.h" #include "bytestream.h" #include "get_bits.h" -#include "unary.h" #include "internal.h" #include "thread.h" +#include "unary.h" #define NB_LEVELS 4 +#define PIXLET_MAGIC 0xDEADBEEF + #define H 0 #define V 1 @@ -47,11 +49,11 @@ typedef struct PixletContext { AVClass *class; GetByteContext gb; - GetBitContext gbit; + GetBitContext bc; int levels; int depth; - int h, w; + int w, h; int16_t *filter[2]; int16_t *prediction; @@ -59,38 +61,10 @@ typedef struct PixletContext { SubBand band[4][NB_LEVELS * 3 + 1]; } PixletContext; -static int init_decoder(AVCodecContext *avctx) +static av_cold int pixlet_init(AVCodecContext *avctx) { - PixletContext *ctx = avctx->priv_data; - int i, plane; - - ctx->filter[0] = av_malloc_array(ctx->h, sizeof(int16_t)); - ctx->filter[1] = av_malloc_array(FFMAX(ctx->h, ctx->w) + 16, sizeof(int16_t)); - ctx->prediction = av_malloc_array((ctx->w >> NB_LEVELS), sizeof(int16_t)); - if (!ctx->filter[0] || !ctx->filter[1] || !ctx->prediction) - return AVERROR(ENOMEM); - - for (plane = 0; plane < 3; plane++) { - unsigned shift = plane > 0; - unsigned w = ctx->w >> shift; - unsigned h = ctx->h >> shift; - - ctx->band[plane][0].width = w >> NB_LEVELS; - ctx->band[plane][0].height = h >> NB_LEVELS; - ctx->band[plane][0].size = (w >> NB_LEVELS) * (h >> NB_LEVELS); - - for (i = 0; i < NB_LEVELS * 3; i++) { - unsigned scale = ctx->levels - (i / 3); - - ctx->band[plane][i + 1].width = w >> scale; - ctx->band[plane][i + 1].height = h >> scale; - ctx->band[plane][i + 1].size = (w >> scale) * (h >> scale); - - ctx->band[plane][i + 1].x = (w >> scale) * (((i + 1) % 3) != 2); - ctx->band[plane][i + 1].y = (h >> scale) * (((i + 1) % 3) != 1); - } - } - + avctx->pix_fmt = AV_PIX_FMT_YUV420P16; + avctx->color_range = AVCOL_RANGE_JPEG; return 0; } @@ -112,17 +86,46 @@ static av_cold int pixlet_close(AVCodecContext *avctx) return 0; } -static av_cold int pixlet_init(AVCodecContext *avctx) +static int init_decoder(AVCodecContext *avctx) { - avctx->pix_fmt = AV_PIX_FMT_YUV420P16; - avctx->color_range = AVCOL_RANGE_JPEG; + PixletContext *ctx = avctx->priv_data; + int i, plane; + + ctx->filter[0] = av_malloc_array(ctx->h, sizeof(int16_t)); + ctx->filter[1] = av_malloc_array(FFMAX(ctx->h, ctx->w) + 16, sizeof(int16_t)); + ctx->prediction = av_malloc_array((ctx->w >> NB_LEVELS), sizeof(int16_t)); + if (!ctx->filter[0] || !ctx->filter[1] || !ctx->prediction) + return AVERROR(ENOMEM); + + for (plane = 0; plane < 3; plane++) { + unsigned shift = plane > 0; + unsigned w = ctx->w >> shift; + unsigned h = ctx->h >> shift; + + ctx->band[plane][0].width = w >> NB_LEVELS; + ctx->band[plane][0].height = h >> NB_LEVELS; + ctx->band[plane][0].size = (w >> NB_LEVELS) * (h >> NB_LEVELS); + + for (i = 0; i < NB_LEVELS * 3; i++) { + unsigned scale = ctx->levels - (i / 3); + + ctx->band[plane][i + 1].width = w >> scale; + ctx->band[plane][i + 1].height = h >> scale; + ctx->band[plane][i + 1].size = (w >> scale) * (h >> scale); + + ctx->band[plane][i + 1].x = (w >> scale) * (((i + 1) % 3) != 2); + ctx->band[plane][i + 1].y = (h >> scale) * (((i + 1) % 3) != 1); + } + } + return 0; } -static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, int width, ptrdiff_t stride) +static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, + int width, ptrdiff_t stride) { PixletContext *ctx = avctx->priv_data; - GetBitContext *b = &ctx->gbit; + GetBitContext *bc = &ctx->bc; unsigned cnt1, nbits, k, j = 0, i = 0; int64_t value, state = 3; int rlen, escape, flag = 0; @@ -130,45 +133,45 @@ static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, int wi while (i < size) { nbits = FFMIN(ff_clz((state >> 8) + 3) ^ 0x1F, 14); - cnt1 = get_unary(b, 0, 8); + cnt1 = get_unary(bc, 0, 8); if (cnt1 < 8) { - value = show_bits(b, nbits); + value = show_bits(bc, nbits); if (value <= 1) { - skip_bits(b, nbits - 1); + skip_bits(bc, nbits - 1); escape = ((1 << nbits) - 1) * cnt1; } else { - skip_bits(b, nbits); + skip_bits(bc, nbits); escape = value + ((1 << nbits) - 1) * cnt1 - 1; } } else { - escape = get_bits(b, 16); + escape = get_bits(bc, 16); } - value = -((escape + flag) & 1) | 1; + value = -((escape + flag) & 1) | 1; dst[j++] = value * ((escape + flag + 1) >> 1); i++; if (j == width) { - j = 0; + j = 0; dst += stride; } state = 120 * (escape + flag) + state - (120 * state >> 8); - flag = 0; + flag = 0; if (state * 4ULL > 0xFF || i >= size) continue; - nbits = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; + nbits = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; escape = av_mod_uintp2(16383, nbits); - cnt1 = get_unary(b, 0, 8); + cnt1 = get_unary(bc, 0, 8); if (cnt1 > 7) { - rlen = get_bits(b, 16); + rlen = get_bits(bc, 16); } else { - value = show_bits(b, nbits); + value = show_bits(bc, nbits); if (value > 1) { - skip_bits(b, nbits); + skip_bits(bc, nbits); rlen = value + escape * cnt1 - 1; } else { - skip_bits(b, nbits - 1); + skip_bits(bc, nbits - 1); rlen = escape * cnt1; } } @@ -180,31 +183,32 @@ static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, int wi for (k = 0; k < rlen; k++) { dst[j++] = 0; if (j == width) { - j = 0; + j = 0; dst += stride; } } state = 0; - flag = rlen < 0xFFFF ? 1 : 0; + flag = rlen < 0xFFFF ? 1 : 0; } - align_get_bits(b); - return get_bits_count(b) >> 3; + align_get_bits(bc); + return get_bits_count(bc) >> 3; } -static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, int size, - int c, int a, int d, +static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, + int size, int c, int a, int d, int width, ptrdiff_t stride) { PixletContext *ctx = avctx->priv_data; - GetBitContext *b = &ctx->gbit; + GetBitContext *bc = &ctx->bc; unsigned cnt1, shbits, rlen, nbits, length, i = 0, j = 0, k; int ret, escape, pfx, value, yflag, xflag, flag = 0; int64_t state = 3, tmp; - if ((ret = init_get_bits8(b, src, bytestream2_get_bytes_left(&ctx->gb))) < 0) - return ret; + ret = init_get_bits8(bc, src, bytestream2_get_bytes_left(&ctx->gb)); + if (ret < 0) + return ret; if (a ^ (a >> 31)) { nbits = 33 - ff_clz(a ^ (a >> 31)); @@ -217,26 +221,24 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i length = 25 - nbits; while (i < size) { - if (state >> 8 != -3) { + if (state >> 8 != -3) value = ff_clz((state >> 8) + 3) ^ 0x1F; - } else { + else value = -1; - } - - cnt1 = get_unary(b, 0, length); + cnt1 = get_unary(bc, 0, length); if (cnt1 >= length) { - cnt1 = get_bits(b, nbits); + cnt1 = get_bits(bc, nbits); } else { pfx = 14 + ((((uint64_t)(value - 14)) >> 32) & (value - 14)); if (pfx < 1 || pfx > 25) return AVERROR_INVALIDDATA; cnt1 *= (1 << pfx) - 1; - shbits = show_bits(b, pfx); + shbits = show_bits(bc, pfx); if (shbits <= 1) { - skip_bits(b, pfx - 1); + skip_bits(bc, pfx - 1); } else { - skip_bits(b, pfx); + skip_bits(bc, pfx); cnt1 += shbits - 1; } } @@ -248,14 +250,14 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i value = 0; } else { xflag &= 1u; - tmp = (int64_t)c * ((yflag + 1) >> 1) + (c >> 1); - value = xflag + (tmp ^ -xflag); + tmp = (int64_t)c * ((yflag + 1) >> 1) + (c >> 1); + value = xflag + (tmp ^ -xflag); } i++; dst[j++] = value; if (j == width) { - j = 0; + j = 0; dst += stride; } state += (int64_t)d * (uint64_t)yflag - ((int64_t)(d * (uint64_t)state) >> 8); @@ -265,25 +267,26 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i if ((uint64_t)state > 0xFF / 4 || i >= size) continue; - pfx = ((state + 8) >> 5) + (state ? ff_clz(state): 32) - 24; + pfx = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; escape = av_mod_uintp2(16383, pfx); - cnt1 = get_unary(b, 0, 8); + cnt1 = get_unary(bc, 0, 8); if (cnt1 < 8) { if (pfx < 1 || pfx > 25) return AVERROR_INVALIDDATA; - value = show_bits(b, pfx); + + value = show_bits(bc, pfx); if (value > 1) { - skip_bits(b, pfx); + skip_bits(bc, pfx); rlen = value + escape * cnt1 - 1; } else { - skip_bits(b, pfx - 1); + skip_bits(bc, pfx - 1); rlen = escape * cnt1; } } else { - if (get_bits1(b)) - value = get_bits(b, 16); + if (get_bits1(bc)) + value = get_bits(bc, 16); else - value = get_bits(b, 8); + value = get_bits(bc, 8); rlen = value + 8 * escape; } @@ -295,20 +298,21 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i for (k = 0; k < rlen; k++) { dst[j++] = 0; if (j == width) { - j = 0; + j = 0; dst += stride; } } state = 0; - flag = rlen < 0xFFFF ? 1 : 0; + flag = rlen < 0xFFFF ? 1 : 0; } - align_get_bits(b); - return get_bits_count(b) >> 3; + align_get_bits(bc); + return get_bits_count(bc) >> 3; } -static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame *frame) +static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, + int plane, AVFrame *frame) { PixletContext *ctx = avctx->priv_data; ptrdiff_t stride = frame->linesize[plane] / 2; @@ -319,15 +323,16 @@ static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame int32_t b = bytestream2_get_be32(&ctx->gb); int32_t c = bytestream2_get_be32(&ctx->gb); int32_t d = bytestream2_get_be32(&ctx->gb); - int16_t *dest = (int16_t *)frame->data[plane] + ctx->band[plane][i + 1].x + - stride * ctx->band[plane][i + 1].y; + int16_t *dest = (int16_t *)frame->data[plane] + + ctx->band[plane][i + 1].x + + ctx->band[plane][i + 1].y * stride; unsigned size = ctx->band[plane][i + 1].size; - uint32_t magic; + uint32_t magic = bytestream2_get_be32(&ctx->gb); - magic = bytestream2_get_be32(&ctx->gb); - if (magic != 0xDEADBEEF) { - av_log(avctx, AV_LOG_ERROR, "wrong magic number: 0x%08"PRIX32 - " for plane %d, band %d\n", magic, plane, i); + if (magic != PIXLET_MAGIC) { + av_log(avctx, AV_LOG_ERROR, + "wrong magic number: 0x%08"PRIX32" for plane %d, band %d\n", + magic, plane, i); return AVERROR_INVALIDDATA; } @@ -338,7 +343,9 @@ static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame c, (b >= FFABS(a)) ? b : a, d, ctx->band[plane][i + 1].width, stride); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in highpass coefficients for plane %d, band %d\n", plane, i); + av_log(avctx, AV_LOG_ERROR, + "error in highpass coefficients for plane %d, band %d\n", + plane, i); return ret; } bytestream2_skip(&ctx->gb, ret); @@ -347,7 +354,8 @@ static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame return 0; } -static void lowpass_prediction(int16_t *dst, int16_t *pred, int width, int height, ptrdiff_t stride) +static void lowpass_prediction(int16_t *dst, int16_t *pred, + int width, int height, ptrdiff_t stride) { int16_t val; int i, j; @@ -373,8 +381,8 @@ static void filterfn(int16_t *dest, int16_t *tmp, unsigned size, int64_t scale) int64_t value; hsize = size >> 1; - low = tmp + 4; - high = &low[hsize + 8]; + low = tmp + 4; + high = &low[hsize + 8]; memcpy(low, dest, size); memcpy(high, dest + hsize, size); @@ -411,29 +419,28 @@ static void filterfn(int16_t *dest, int16_t *tmp, unsigned size, int64_t scale) } } -static void reconstruction(AVCodecContext *avctx, - int16_t *dest, unsigned width, unsigned height, ptrdiff_t stride, int nb_levels, - int64_t *scaling_H, int64_t *scaling_V) +static void reconstruction(AVCodecContext *avctx, int16_t *dest, + unsigned width, unsigned height, ptrdiff_t stride, + int64_t *scaling_h, int64_t *scaling_v) { PixletContext *ctx = avctx->priv_data; unsigned scaled_width, scaled_height; - int64_t scale_H, scale_V; int16_t *ptr, *tmp; int i, j, k; - scaled_height = height >> nb_levels; - scaled_width = width >> nb_levels; - tmp = ctx->filter[0]; + scaled_width = width >> NB_LEVELS; + scaled_height = height >> NB_LEVELS; + tmp = ctx->filter[0]; - for (i = 0; i < nb_levels; i++) { + for (i = 0; i < NB_LEVELS; i++) { + int64_t scale_v = scaling_v[i]; + int64_t scale_h = scaling_h[i]; scaled_width <<= 1; scaled_height <<= 1; - scale_H = scaling_H[i]; - scale_V = scaling_V[i]; ptr = dest; for (j = 0; j < scaled_height; j++) { - filterfn(ptr, ctx->filter[1], scaled_width, scale_V); + filterfn(ptr, ctx->filter[1], scaled_width, scale_v); ptr += stride; } @@ -441,10 +448,10 @@ static void reconstruction(AVCodecContext *avctx, ptr = dest + j; for (k = 0; k < scaled_height; k++) { tmp[k] = *ptr; - ptr += stride; + ptr += stride; } - filterfn(tmp, ctx->filter[1], scaled_height, scale_H); + filterfn(tmp, ctx->filter[1], scaled_height, scale_h); ptr = dest + j; for (k = 0; k < scaled_height; k++) { @@ -501,11 +508,12 @@ static void postprocess_chroma(AVFrame *frame, int w, int h, int depth) } } -static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFrame *frame) +static int decode_plane(AVCodecContext *avctx, int plane, + AVPacket *avpkt, AVFrame *frame) { PixletContext *ctx = avctx->priv_data; - ptrdiff_t stride = frame->linesize[plane] / 2; - unsigned shift = plane > 0; + ptrdiff_t stride = frame->linesize[plane] / 2; + unsigned shift = plane > 0; int16_t *dst; int i, ret; @@ -522,22 +530,28 @@ static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFra bytestream2_skip(&ctx->gb, 4); - dst = (int16_t *)frame->data[plane]; + dst = (int16_t *)frame->data[plane]; dst[0] = sign_extend(bytestream2_get_be16(&ctx->gb), 16); - if ((ret = init_get_bits8(&ctx->gbit, avpkt->data + bytestream2_tell(&ctx->gb), - bytestream2_get_bytes_left(&ctx->gb))) < 0) + ret = init_get_bits8(&ctx->bc, avpkt->data + bytestream2_tell(&ctx->gb), + bytestream2_get_bytes_left(&ctx->gb)); + if (ret < 0) return ret; - ret = read_low_coeffs(avctx, dst + 1, ctx->band[plane][0].width - 1, ctx->band[plane][0].width - 1, 0); + ret = read_low_coeffs(avctx, dst + 1, ctx->band[plane][0].width - 1, + ctx->band[plane][0].width - 1, 0); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in lowpass coefficients for plane %d, top row\n", plane); + av_log(avctx, AV_LOG_ERROR, + "error in lowpass coefficients for plane %d, top row\n", plane); return ret; } - ret = read_low_coeffs(avctx, dst + stride, ctx->band[plane][0].height - 1, 1, stride); + ret = read_low_coeffs(avctx, dst + stride, + ctx->band[plane][0].height - 1, 1, stride); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in lowpass coefficients for plane %d, left column\n", plane); + av_log(avctx, AV_LOG_ERROR, + "error in lowpass coefficients for plane %d, left column\n", + plane); return ret; } @@ -545,7 +559,8 @@ static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFra (ctx->band[plane][0].width - 1) * (ctx->band[plane][0].height - 1), ctx->band[plane][0].width - 1, stride); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in lowpass coefficients for plane %d, rest\n", plane); + av_log(avctx, AV_LOG_ERROR, + "error in lowpass coefficients for plane %d, rest\n", plane); return ret; } @@ -559,11 +574,12 @@ static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFra if (ret < 0) return ret; - lowpass_prediction(dst, ctx->prediction, - ctx->band[plane][0].width, ctx->band[plane][0].height, stride); + lowpass_prediction(dst, ctx->prediction, ctx->band[plane][0].width, + ctx->band[plane][0].height, stride); - reconstruction(avctx, (int16_t *)frame->data[plane], ctx->w >> shift, ctx->h >> shift, - stride, NB_LEVELS, ctx->scaling[plane][H], ctx->scaling[plane][V]); + reconstruction(avctx, (int16_t *)frame->data[plane], ctx->w >> shift, + ctx->h >> shift, stride, ctx->scaling[plane][H], + ctx->scaling[plane][V]); return 0; } @@ -664,14 +680,15 @@ static int pixlet_init_thread_copy(AVCodecContext *avctx) { PixletContext *ctx = avctx->priv_data; - ctx->filter[0] = NULL; - ctx->filter[1] = NULL; + ctx->filter[0] = NULL; + ctx->filter[1] = NULL; ctx->prediction = NULL; - ctx->w = ctx->h = 0; + ctx->w = 0; + ctx->h = 0; return 0; } -#endif +#endif /* HAVE_THREADS */ AVCodec ff_pixlet_decoder = { .name = "pixlet", diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 0d6612ccc..f93f200bb 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -25,6 +25,7 @@ #include "libavutil/bprint.h" #include "libavutil/imgutils.h" #include "libavutil/stereo3d.h" +#include "libavutil/mastering_display_metadata.h" #include "avcodec.h" #include "bytestream.h" @@ -523,9 +524,9 @@ static int decode_text_chunk(PNGDecContext *s, uint32_t length, int compressed, if ((ret = decode_zbuf(&bp, data, data_end)) < 0) return ret; text_len = bp.len; - av_bprint_finalize(&bp, (char **)&text); - if (!text) - return AVERROR(ENOMEM); + ret = av_bprint_finalize(&bp, (char **)&text); + if (ret < 0) + return ret; } else { text = (uint8_t *)data; text_len = data_end - text; @@ -661,10 +662,10 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { avctx->pix_fmt = AV_PIX_FMT_YA16BE; } else { - av_log(avctx, AV_LOG_ERROR, "unsupported bit depth %d " - "and color type %d\n", - s->bit_depth, s->color_type); - return AVERROR_INVALIDDATA; + avpriv_report_missing_feature(avctx, + "Bit depth %d color type %d", + s->bit_depth, s->color_type); + return AVERROR_PATCHWELCOME; } if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE) { @@ -861,7 +862,9 @@ static int decode_iccp_chunk(PNGDecContext *s, int length, AVFrame *f) if ((ret = decode_zbuf(&bp, s->gb.buffer, s->gb.buffer + length)) < 0) return ret; - av_bprint_finalize(&bp, (char **)&data); + ret = av_bprint_finalize(&bp, (char **)&data); + if (ret < 0) + return ret; sd = av_frame_new_side_data(f, AV_FRAME_DATA_ICC_PROFILE, bp.len); if (!sd) { @@ -1165,7 +1168,7 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, AVDictionary **metadatap = NULL; uint32_t tag, length; int decode_next_dat = 0; - int ret; + int i, ret; for (;;) { length = bytestream2_get_bytes_left(&s->gb); @@ -1287,6 +1290,42 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, goto fail; break; } + case MKTAG('c', 'H', 'R', 'M'): { + AVMasteringDisplayMetadata *mdm = av_mastering_display_metadata_create_side_data(p); + if (!mdm) { + ret = AVERROR(ENOMEM); + goto fail; + } + + mdm->white_point[0] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + mdm->white_point[1] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + + /* RGB Primaries */ + for (i = 0; i < 3; i++) { + mdm->display_primaries[i][0] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + mdm->display_primaries[i][1] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + } + + mdm->has_primaries = 1; + bytestream2_skip(&s->gb, 4); /* crc */ + break; + } + case MKTAG('g', 'A', 'M', 'A'): { + AVBPrint bp; + char *gamma_str; + int num = bytestream2_get_be32(&s->gb); + + av_bprint_init(&bp, 0, -1); + av_bprintf(&bp, "%i/%i", num, 100000); + ret = av_bprint_finalize(&bp, &gamma_str); + if (ret < 0) + return ret; + + av_dict_set(&p->metadata, "gamma", gamma_str, AV_DICT_DONT_STRDUP_VAL); + + bytestream2_skip(&s->gb, 4); /* crc */ + break; + } case MKTAG('I', 'E', 'N', 'D'): if (!(s->pic_state & PNG_ALLIMAGE)) av_log(avctx, AV_LOG_ERROR, "IEND without all image\n"); diff --git a/libavcodec/ppc/fft_init.c b/libavcodec/ppc/fft_init.c index 57d7c80ea..733e58b4c 100644 --- a/libavcodec/ppc/fft_init.c +++ b/libavcodec/ppc/fft_init.c @@ -42,7 +42,7 @@ void ff_fft_calc_altivec(FFTContext *s, FFTComplex *z); void ff_fft_calc_interleave_altivec(FFTContext *s, FFTComplex *z); #endif -#if HAVE_GNU_AS && HAVE_ALTIVEC +#if HAVE_GNU_AS && HAVE_ALTIVEC && (HAVE_BIGENDIAN || HAVE_VSX) static void imdct_half_altivec(FFTContext *s, FFTSample *output, const FFTSample *input) { int j, k; @@ -146,11 +146,11 @@ static void imdct_calc_altivec(FFTContext *s, FFTSample *output, const FFTSample p1[k] = vec_perm(b, b, vcprm(3,2,1,0)); } } -#endif /* HAVE_GNU_AS && HAVE_ALTIVEC && HAVE_BIGENDIAN */ +#endif /* HAVE_GNU_AS && HAVE_ALTIVEC && (HAVE_BIGENDIAN || HAVE_VSX) */ av_cold void ff_fft_init_ppc(FFTContext *s) { -#if HAVE_GNU_AS && HAVE_ALTIVEC +#if HAVE_GNU_AS && HAVE_ALTIVEC && (HAVE_BIGENDIAN || HAVE_VSX) if (!PPC_ALTIVEC(av_get_cpu_flags())) return; diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c index e84a058d0..f510544dd 100644 --- a/libavcodec/ppc/h264dsp.c +++ b/libavcodec/ppc/h264dsp.c @@ -771,12 +771,12 @@ void biweight_h264_W_altivec(uint8_t *dst, uint8_t *src, int stride, int height, } #define H264_WEIGHT(W) \ -static void weight_h264_pixels ## W ## _altivec(uint8_t *block, int stride, int height, \ +static void weight_h264_pixels ## W ## _altivec(uint8_t *block, ptrdiff_t stride, int height, \ int log2_denom, int weight, int offset) \ { \ weight_h264_W_altivec(block, stride, height, log2_denom, weight, offset, W); \ }\ -static void biweight_h264_pixels ## W ## _altivec(uint8_t *dst, uint8_t *src, int stride, int height, \ +static void biweight_h264_pixels ## W ## _altivec(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, \ int log2_denom, int weightd, int weights, int offset) \ { \ biweight_h264_W_altivec(dst, src, stride, height, log2_denom, weightd, weights, offset, W); \ diff --git a/libavcodec/ppc/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c index 4f1952186..a531b6b6e 100644 --- a/libavcodec/ppc/hpeldsp_altivec.c +++ b/libavcodec/ppc/hpeldsp_altivec.c @@ -84,7 +84,7 @@ void ff_avg_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li /* next one assumes that ((line_size % 8) == 0) */ static void avg_pixels8_altivec(uint8_t * block, const uint8_t * pixels, ptrdiff_t line_size, int h) { - register vector unsigned char pixelsv1, pixelsv2, pixelsv, blockv; + register vector unsigned char pixelsv, blockv; int i; for (i = 0; i < h; i++) { diff --git a/libavcodec/ppc/svq1enc_altivec.c b/libavcodec/ppc/svq1enc_altivec.c index f63f08660..aa66b4099 100644 --- a/libavcodec/ppc/svq1enc_altivec.c +++ b/libavcodec/ppc/svq1enc_altivec.c @@ -31,7 +31,7 @@ #if HAVE_ALTIVEC static int ssd_int8_vs_int16_altivec(const int8_t *pix1, const int16_t *pix2, - int size) + intptr_t size) { int i, size16 = size >> 4; vector signed char vpix1; diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c index 0f791de97..d97e264e4 100644 --- a/libavcodec/proresdec2.c +++ b/libavcodec/proresdec2.c @@ -517,8 +517,8 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int int luma_stride, chroma_stride; int y_data_size, u_data_size, v_data_size, a_data_size; uint8_t *dest_y, *dest_u, *dest_v, *dest_a; - int16_t qmat_luma_scaled[64]; - int16_t qmat_chroma_scaled[64]; + LOCAL_ALIGNED_16(int16_t, qmat_luma_scaled, [64]); + LOCAL_ALIGNED_16(int16_t, qmat_chroma_scaled,[64]); int mb_x_shift; int ret; @@ -598,8 +598,9 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int } else { size_t mb_max_x = slice->mb_count << (mb_x_shift - 1); - for (size_t i = 0; i < 16; ++i) - for (size_t j = 0; j < mb_max_x; ++j) { + size_t i, j; + for (i = 0; i < 16; ++i) + for (j = 0; j < mb_max_x; ++j) { *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = 511; *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = 511; } diff --git a/libavcodec/proresdec_lgpl.c b/libavcodec/proresdec_lgpl.c index bc5bdb5a4..c86d433f5 100644 --- a/libavcodec/proresdec_lgpl.c +++ b/libavcodec/proresdec_lgpl.c @@ -177,6 +177,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, avctx->color_primaries = buf[14]; avctx->color_trc = buf[15]; avctx->colorspace = buf[16]; + avctx->color_range = AVCOL_RANGE_MPEG; ctx->qmat_changed = 0; ptr = buf + 20; diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 2c702c737..25aa3e2cd 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -246,7 +246,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, { int err = 0; - if (dst != src && (for_user || !(av_codec_get_codec_descriptor(src)->props & AV_CODEC_PROP_INTRA_ONLY))) { + 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; @@ -262,11 +262,6 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, dst->bits_per_coded_sample = src->bits_per_coded_sample; dst->sample_aspect_ratio = src->sample_aspect_ratio; -#if FF_API_AFD -FF_DISABLE_DEPRECATION_WARNINGS - dst->dtg_active_format = src->dtg_active_format; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_AFD */ dst->profile = src->profile; dst->level = src->level; @@ -733,10 +728,6 @@ int ff_frame_thread_init(AVCodecContext *avctx) FrameThreadContext *fctx; int i, err = 0; -#if HAVE_W32THREADS - w32thread_init(); -#endif - if (!thread_count) { int nb_cpus = av_cpu_count(); #if FF_API_DEBUG_MV diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c index d659f9b0b..77cfe3c9f 100644 --- a/libavcodec/pthread_slice.c +++ b/libavcodec/pthread_slice.c @@ -132,10 +132,6 @@ int ff_slice_thread_init(AVCodecContext *avctx) int thread_count = avctx->thread_count; static void (*mainfunc)(void *); -#if HAVE_W32THREADS - w32thread_init(); -#endif - // 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 && diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index 3a0bc6f76..82cc528a3 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -434,7 +434,7 @@ static int decode_frame(AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp); if (bppcnt == 3 && bpp == 8) { avctx->pix_fmt = AV_PIX_FMT_RGB24; - } else if (bppcnt == 3 && bpp == 5) { + } else if (bppcnt == 3 && bpp == 5 || bppcnt == 2 && bpp == 8) { avctx->pix_fmt = AV_PIX_FMT_RGB555; } else if (bppcnt == 4 && bpp == 8) { avctx->pix_fmt = AV_PIX_FMT_ARGB; diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 56ca9df26..250b4e61e 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -56,6 +57,8 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id) case AV_CODEC_ID_VP8: return MFX_CODEC_VP8; #endif + case AV_CODEC_ID_MJPEG: + return MFX_CODEC_JPEG; default: break; } @@ -590,6 +593,11 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, "Error setting a HW handle"); } + err = MFXJoinSession(parent_session, session); + if (err != MFX_ERR_NONE) + return ff_qsv_print_error(avctx, err, + "Error joining session"); + ret = qsv_load_plugins(session, load_plugins, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index c00817f1d..55fe59b53 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -41,6 +41,19 @@ #include "qsv_internal.h" #include "qsvdec.h" +const AVCodecHWConfigInternal *ff_qsv_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_QSV, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | + AV_CODEC_HW_CONFIG_METHOD_AD_HOC, + .device_type = AV_HWDEVICE_TYPE_QSV, + }, + .hwaccel = NULL, + }, + NULL +}; + static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session, AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref) { diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index 4e86e4b7f..5b7b03a48 100644 --- a/libavcodec/qsvdec.h +++ b/libavcodec/qsvdec.h @@ -33,6 +33,7 @@ #include "libavutil/pixfmt.h" #include "avcodec.h" +#include "hwaccel.h" #include "qsv_internal.h" typedef struct QSVContext { @@ -70,6 +71,8 @@ typedef struct QSVContext { int nb_ext_buffers; } QSVContext; +extern const AVCodecHWConfigInternal *ff_qsv_hw_configs[]; + int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, AVFrame *frame, int *got_frame, AVPacket *pkt); diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c index a6b53cce8..5e0067335 100644 --- a/libavcodec/qsvdec_h2645.c +++ b/libavcodec/qsvdec_h2645.c @@ -171,23 +171,20 @@ static void qsv_decode_flush(AVCodecContext *avctx) ff_qsv_decode_flush(avctx, &s->qsv); } +#if defined(_WIN32) +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW +#else +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW +#endif + #define OFFSET(x) offsetof(QSVH2645Context, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM -#if CONFIG_HEVC_QSV_HWACCEL -AVHWAccel ff_hevc_qsv_hwaccel = { - .name = "hevc_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_HEVC, - .pix_fmt = AV_PIX_FMT_QSV, -}; -#endif - #if CONFIG_HEVC_QSV_DECODER static const AVOption hevc_options[] = { { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD }, - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_DEFAULT }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VD, "load_plugin" }, { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VD, "load_plugin" }, { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VD, "load_plugin" }, @@ -214,22 +211,15 @@ AVCodec ff_hevc_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &hevc_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .hw_configs = ff_qsv_hw_configs, .bsfs = "hevc_mp4toannexb", -}; -#endif - -#if CONFIG_H264_QSV_HWACCEL -AVHWAccel ff_h264_qsv_hwaccel = { - .name = "h264_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_QSV, + .wrapper_name = "qsv", }; #endif @@ -256,12 +246,14 @@ AVCodec ff_h264_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .hw_configs = ff_qsv_hw_configs, .bsfs = "h264_mp4toannexb", + .wrapper_name = "qsv", }; #endif diff --git a/libavcodec/qsvdec_other.c b/libavcodec/qsvdec_other.c index b94093d53..3c872dcfc 100644 --- a/libavcodec/qsvdec_other.c +++ b/libavcodec/qsvdec_other.c @@ -60,6 +60,11 @@ static av_cold int qsv_decode_close(AVCodecContext *avctx) { QSVOtherContext *s = avctx->priv_data; +#if CONFIG_VP8_QSV_DECODER + if (avctx->codec_id == AV_CODEC_ID_VP8) + av_freep(&s->qsv.load_plugins); +#endif + ff_qsv_decode_close(&s->qsv); qsv_clear_buffers(s); @@ -158,15 +163,6 @@ static const AVOption options[] = { { NULL }, }; -#if CONFIG_MPEG2_QSV_HWACCEL -AVHWAccel ff_mpeg2_qsv_hwaccel = { - .name = "mpeg2_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .pix_fmt = AV_PIX_FMT_QSV, -}; -#endif - #if CONFIG_MPEG2_QSV_DECODER static const AVClass mpeg2_qsv_class = { .class_name = "mpeg2_qsv", @@ -185,20 +181,13 @@ AVCodec ff_mpeg2_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &mpeg2_qsv_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, -}; -#endif - -#if CONFIG_VC1_QSV_HWACCEL -AVHWAccel ff_vc1_qsv_hwaccel = { - .name = "vc1_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VC1, - .pix_fmt = AV_PIX_FMT_QSV, + .hw_configs = ff_qsv_hw_configs, + .wrapper_name = "qsv", }; #endif @@ -220,20 +209,13 @@ AVCodec ff_vc1_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &vc1_qsv_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, -}; -#endif - -#if CONFIG_VP8_QSV_HWACCEL -AVHWAccel ff_vp8_qsv_hwaccel = { - .name = "vp8_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP8, - .pix_fmt = AV_PIX_FMT_QSV, + .hw_configs = ff_qsv_hw_configs, + .wrapper_name = "qsv", }; #endif @@ -255,10 +237,12 @@ AVCodec ff_vp8_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &vp8_qsv_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .hw_configs = ff_qsv_hw_configs, + .wrapper_name = "qsv", }; #endif diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 5eb506fb7..fee2f9f0e 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -287,6 +287,12 @@ static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) return AVERROR(EINVAL); } + if (!want_qscale && avctx->global_quality > 0 && !QSV_HAVE_ICQ){ + av_log(avctx, AV_LOG_ERROR, + "ICQ ratecontrol mode requested, but is not supported by this SDK version\n"); + return AVERROR(ENOSYS); + } + if (want_qscale) { rc_mode = MFX_RATECONTROL_CQP; rc_desc = "constant quantization parameter (CQP)"; @@ -345,6 +351,64 @@ static int rc_supported(QSVEncContext *q) return 1; } +static int init_video_param_jpeg(AVCodecContext *avctx, QSVEncContext *q) +{ + enum AVPixelFormat sw_format = avctx->pix_fmt == AV_PIX_FMT_QSV ? + avctx->sw_pix_fmt : avctx->pix_fmt; + const AVPixFmtDescriptor *desc; + int ret; + + ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); + if (ret < 0) + return AVERROR_BUG; + q->param.mfx.CodecId = ret; + + if (avctx->level > 0) + q->param.mfx.CodecLevel = avctx->level; + q->param.mfx.CodecProfile = q->profile; + + desc = av_pix_fmt_desc_get(sw_format); + if (!desc) + return AVERROR_BUG; + + ff_qsv_map_pixfmt(sw_format, &q->param.mfx.FrameInfo.FourCC); + + q->param.mfx.FrameInfo.CropX = 0; + q->param.mfx.FrameInfo.CropY = 0; + q->param.mfx.FrameInfo.CropW = avctx->width; + q->param.mfx.FrameInfo.CropH = avctx->height; + q->param.mfx.FrameInfo.AspectRatioW = avctx->sample_aspect_ratio.num; + q->param.mfx.FrameInfo.AspectRatioH = avctx->sample_aspect_ratio.den; + q->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + q->param.mfx.FrameInfo.BitDepthLuma = desc->comp[0].depth; + q->param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth; + q->param.mfx.FrameInfo.Shift = desc->comp[0].depth > 8; + + q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, 16); + q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, 16); + + if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + q->param.mfx.FrameInfo.Width = frames_hwctx->surfaces[0].Info.Width; + q->param.mfx.FrameInfo.Height = frames_hwctx->surfaces[0].Info.Height; + } + + if (avctx->framerate.den > 0 && avctx->framerate.num > 0) { + q->param.mfx.FrameInfo.FrameRateExtN = avctx->framerate.num; + q->param.mfx.FrameInfo.FrameRateExtD = avctx->framerate.den; + } else { + q->param.mfx.FrameInfo.FrameRateExtN = avctx->time_base.den; + q->param.mfx.FrameInfo.FrameRateExtD = avctx->time_base.num; + } + + q->param.mfx.Interleaved = 1; + q->param.mfx.Quality = av_clip(avctx->global_quality, 1, 100); + q->param.mfx.RestartInterval = 0; + + return 0; +} + static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) { enum AVPixelFormat sw_format = avctx->pix_fmt == AV_PIX_FMT_QSV ? @@ -437,6 +501,7 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) #if QSV_HAVE_VCM case MFX_RATECONTROL_VCM: #endif + q->param.mfx.BufferSizeInKB = avctx->rc_buffer_size / 8000; q->param.mfx.InitialDelayInKB = avctx->rc_initial_buffer_occupancy / 1000; q->param.mfx.TargetKbps = avctx->bit_rate / 1000; q->param.mfx.MaxKbps = avctx->rc_max_rate / 1000; @@ -474,14 +539,6 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) if (avctx->codec_id != AV_CODEC_ID_HEVC) { q->extco.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; q->extco.Header.BufferSz = sizeof(q->extco); -#if FF_API_CODER_TYPE -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->coder_type != 0) - q->cavlc = avctx->coder_type == FF_CODER_TYPE_VLC; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON - : MFX_CODINGOPTION_UNKNOWN; q->extco.PicTimingSEI = q->pic_timing_sei ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN; @@ -490,6 +547,15 @@ FF_ENABLE_DEPRECATION_WARNINGS q->extco.RateDistortionOpt = q->rdo > 0 ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; if (avctx->codec_id == AV_CODEC_ID_H264) { +#if FF_API_CODER_TYPE +FF_DISABLE_DEPRECATION_WARNINGS + if (avctx->coder_type >= 0) + q->cavlc = avctx->coder_type == FF_CODER_TYPE_VLC; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON + : MFX_CODINGOPTION_UNKNOWN; + if (avctx->strict_std_compliance != FF_COMPLIANCE_NORMAL) q->extco.NalHrdConformance = avctx->strict_std_compliance > FF_COMPLIANCE_NORMAL ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; @@ -533,6 +599,10 @@ FF_ENABLE_DEPRECATION_WARNINGS q->extco2.Trellis = q->trellis; #endif +#if QSV_HAVE_LA_DS + q->extco2.LookAheadDS = q->look_ahead_downsampling; +#endif + #if QSV_HAVE_BREF_TYPE #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS @@ -549,10 +619,6 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2; - -#if QSV_HAVE_LA_DS - q->extco2.LookAheadDS = q->look_ahead_downsampling; -#endif } #endif } @@ -567,6 +633,24 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } +static int qsv_retrieve_enc_jpeg_params(AVCodecContext *avctx, QSVEncContext *q) +{ + int ret = 0; + + ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param); + if (ret < 0) + return ff_qsv_print_error(avctx, ret, + "Error calling GetVideoParam"); + + q->packet_size = q->param.mfx.BufferSizeInKB * 1000; + + // for qsv mjpeg the return value maybe 0 so alloc the buffer + if (q->packet_size == 0) + q->packet_size = q->param.mfx.FrameInfo.Height * q->param.mfx.FrameInfo.Width * 4; + + return 0; +} + static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q) { AVCPBProperties *cpb_props; @@ -760,7 +844,15 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) if (ret < 0) return ret; - ret = init_video_param(avctx, q); + // in the mfxInfoMFX struct, JPEG is different from other codecs + switch (avctx->codec_id) { + case AV_CODEC_ID_MJPEG: + ret = init_video_param_jpeg(avctx, q); + break; + default: + ret = init_video_param(avctx, q); + break; + } if (ret < 0) return ret; @@ -820,7 +912,14 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) ff_qsv_print_warning(avctx, ret, "Warning in encoder initialization"); - ret = qsv_retrieve_enc_params(avctx, q); + switch (avctx->codec_id) { + case AV_CODEC_ID_MJPEG: + ret = qsv_retrieve_enc_jpeg_params(avctx, q); + break; + default: + ret = qsv_retrieve_enc_params(avctx, q); + break; + } if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n"); return ret; diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h index 12e3444b7..88e072811 100644 --- a/libavcodec/qsvenc.h +++ b/libavcodec/qsvenc.h @@ -44,9 +44,23 @@ #define QSV_HAVE_LA QSV_VERSION_ATLEAST(1, 7) #define QSV_HAVE_LA_DS QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_LA_HRD QSV_VERSION_ATLEAST(1, 11) + +#if defined(_WIN32) #define QSV_HAVE_ICQ QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_VCM QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_QVBR QSV_VERSION_ATLEAST(1, 11) +#else +#define QSV_HAVE_ICQ 0 +#define QSV_HAVE_VCM 0 +#define QSV_HAVE_QVBR 0 +#endif + +#if !QSV_HAVE_LA_DS +#define MFX_LOOKAHEAD_DS_UNKNOWN 0 +#define MFX_LOOKAHEAD_DS_OFF 0 +#define MFX_LOOKAHEAD_DS_2x 0 +#define MFX_LOOKAHEAD_DS_4x 0 +#endif #define QSV_COMMON_OPTS \ { "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VE }, \ @@ -70,7 +84,6 @@ { "adaptive_i", "Adaptive I-frame placement", OFFSET(qsv.adaptive_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "adaptive_b", "Adaptive B-frame placement", OFFSET(qsv.adaptive_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "b_strategy", "Strategy to choose between I/P/B-frames", OFFSET(qsv.b_strategy), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ -{ "cavlc", "Enable CAVLC", OFFSET(qsv.cavlc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, \ typedef int SetEncodeCtrlCB (AVCodecContext *avctx, const AVFrame *frame, mfxEncodeCtrl* enc_ctrl); diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 389335f39..09e4c0e59 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -102,6 +102,7 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) static const AVOption options[] = { QSV_COMMON_OPTS + { "cavlc", "Enable CAVLC", OFFSET(qsv.cavlc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "pic_timing_sei", "Insert picture timing SEI with pic_struct_syntax element", OFFSET(qsv.pic_timing_sei), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, { "single_sei_nal_unit", "Put all the SEI messages into one NALU", OFFSET(qsv.single_sei_nal_unit), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, @@ -112,10 +113,13 @@ static const AVOption options[] = { { "look_ahead_depth", "Depth of look ahead in number frames", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE }, #endif #if QSV_HAVE_LA_DS - { "look_ahead_downsampling", NULL, OFFSET(qsv.look_ahead_downsampling), AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" }, + { "look_ahead_downsampling", "Downscaling factor for the frames saved for the lookahead analysis", OFFSET(qsv.look_ahead_downsampling), + AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" }, { "unknown" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, + { "auto" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, { "off" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_OFF }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, { "2x" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_2x }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, + { "4x" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_4x }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, #endif { "int_ref_type", "Intra refresh type", OFFSET(qsv.int_ref_type), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE, "int_ref_type" }, @@ -154,7 +158,9 @@ static const AVCodecDefault qsv_enc_defaults[] = { // same as the x264 default { "g", "250" }, { "bf", "3" }, - { "coder", "ac" }, +#if FF_API_CODER_TYPE + { "coder", "-1" }, +#endif { "flags", "+cgop" }, #if FF_API_PRIVATE_OPT @@ -172,7 +178,7 @@ AVCodec ff_h264_qsv_encoder = { .init = qsv_enc_init, .encode2 = qsv_enc_frame, .close = qsv_enc_close, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, @@ -180,4 +186,5 @@ AVCodec ff_h264_qsv_encoder = { .priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "qsv", }; diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index b0e5ace7c..4339b316a 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -56,6 +56,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) PutByteContext pbc; GetBitContext gb; + H2645RBSP sps_rbsp = { NULL }; H2645NAL sps_nal = { NULL }; HEVCSPS sps = { 0 }; HEVCVPS vps = { 0 }; @@ -69,8 +70,12 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) return AVERROR_UNKNOWN; } + av_fast_padded_malloc(&sps_rbsp.rbsp_buffer, &sps_rbsp.rbsp_buffer_alloc_size, avctx->extradata_size); + if (!sps_rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + /* parse the SPS */ - ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_nal, 1); + ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_rbsp, &sps_nal, 1); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error unescaping the SPS buffer\n"); return ret; @@ -78,7 +83,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) ret = init_get_bits8(&gb, sps_nal.data, sps_nal.size); if (ret < 0) { - av_freep(&sps_nal.rbsp_buffer); + av_freep(&sps_rbsp.rbsp_buffer); return ret; } @@ -87,13 +92,13 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) if (type != HEVC_NAL_SPS) { av_log(avctx, AV_LOG_ERROR, "Unexpected NAL type in the extradata: %d\n", type); - av_freep(&sps_nal.rbsp_buffer); + av_freep(&sps_rbsp.rbsp_buffer); return AVERROR_INVALIDDATA; } get_bits(&gb, 9); ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx); - av_freep(&sps_nal.rbsp_buffer); + av_freep(&sps_rbsp.rbsp_buffer); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n"); return ret; @@ -181,6 +186,9 @@ static av_cold int qsv_enc_init(AVCodecContext *avctx) } } + // HEVC and H264 meaning of the value is shifted by 1, make it consistent + q->qsv.idr_interval++; + ret = ff_qsv_enc_init(avctx, &q->qsv); if (ret < 0) return ret; @@ -209,12 +217,20 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) return ff_qsv_enc_close(avctx, &q->qsv); } +#if defined(_WIN32) +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW +#else +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW +#endif + #define OFFSET(x) offsetof(QSVHEVCEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { QSV_COMMON_OPTS - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" }, + { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT_MAX, VE, "idr_interval" }, + { "begin_only", "Output an IDR-frame only at the beginning of the stream", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "idr_interval" }, + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_DEFAULT }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VE, "load_plugin" }, { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VE, "load_plugin" }, { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VE, "load_plugin" }, @@ -261,7 +277,7 @@ AVCodec ff_hevc_qsv_encoder = { .init = qsv_enc_init, .encode2 = qsv_enc_frame, .close = qsv_enc_close, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, @@ -269,4 +285,5 @@ AVCodec ff_hevc_qsv_encoder = { .priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "qsv", }; diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c new file mode 100644 index 000000000..c18fe9194 --- /dev/null +++ b/libavcodec/qsvenc_jpeg.c @@ -0,0 +1,92 @@ +/* + * Intel MediaSDK QSV based MJPEG 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 + */ + + +#include +#include + +#include + +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "internal.h" +#include "h264.h" +#include "qsv.h" +#include "qsv_internal.h" +#include "qsvenc.h" + +typedef struct QSVMJPEGEncContext { + AVClass *class; + QSVEncContext qsv; +} QSVMJPEGEncContext; + +static av_cold int qsv_enc_init(AVCodecContext *avctx) +{ + QSVMJPEGEncContext *q = avctx->priv_data; + + return ff_qsv_enc_init(avctx, &q->qsv); +} + +static int qsv_enc_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + QSVMJPEGEncContext *q = avctx->priv_data; + + return ff_qsv_encode(avctx, &q->qsv, pkt, frame, got_packet); +} + +static av_cold int qsv_enc_close(AVCodecContext *avctx) +{ + QSVMJPEGEncContext *q = avctx->priv_data; + + return ff_qsv_enc_close(avctx, &q->qsv); +} + +#define OFFSET(x) offsetof(QSVMJPEGEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { NULL }, +}; + +static const AVClass class = { + .class_name = "mjpeg_qsv encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_mjpeg_qsv_encoder = { + .name = "mjpeg_qsv", + .long_name = NULL_IF_CONFIG_SMALL("MJPEG (Intel Quick Sync Video acceleration)"), + .priv_data_size = sizeof(QSVMJPEGEncContext), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MJPEG, + .init = qsv_enc_init, + .encode2 = qsv_enc_frame, + .close = qsv_enc_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE }, + .priv_class = &class, + .wrapper_name = "qsv", +}; diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c index 5b583fb49..a7427d810 100644 --- a/libavcodec/qsvenc_mpeg2.c +++ b/libavcodec/qsvenc_mpeg2.c @@ -104,11 +104,12 @@ AVCodec ff_mpeg2_qsv_encoder = { .init = qsv_enc_init, .encode2 = qsv_enc_frame, .close = qsv_enc_close, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, .priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "qsv", }; diff --git a/libavcodec/raw.h b/libavcodec/raw.h index 24bf4cc55..28a27b1f9 100644 --- a/libavcodec/raw.h +++ b/libavcodec/raw.h @@ -28,6 +28,7 @@ #define AVCODEC_RAW_H #include "avcodec.h" +#include "internal.h" #include "libavutil/internal.h" typedef struct PixelFormatTag { @@ -41,7 +42,7 @@ 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 const PixelFormatTag avpriv_pix_fmt_bps_avi[]; -extern av_export const PixelFormatTag avpriv_pix_fmt_bps_mov[]; +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/libavcodec/resample.c b/libavcodec/resample.c deleted file mode 100644 index 4c5eb9f10..000000000 --- a/libavcodec/resample.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * samplerate conversion for both audio and video - * 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 - * samplerate conversion for both audio and video - */ - -#include - -#include "avcodec.h" -#include "audioconvert.h" -#include "libavutil/opt.h" -#include "libavutil/mem.h" -#include "libavutil/samplefmt.h" - -#if FF_API_AVCODEC_RESAMPLE -FF_DISABLE_DEPRECATION_WARNINGS - -#define MAX_CHANNELS 8 - -struct AVResampleContext; - -static const char *context_to_name(void *ptr) -{ - return "audioresample"; -} - -static const AVOption options[] = {{NULL}}; -static const AVClass audioresample_context_class = { - "ReSampleContext", context_to_name, options, LIBAVUTIL_VERSION_INT -}; - -struct ReSampleContext { - struct AVResampleContext *resample_context; - short *temp[MAX_CHANNELS]; - int temp_len; - float ratio; - /* channel convert */ - int input_channels, output_channels, filter_channels; - AVAudioConvert *convert_ctx[2]; - enum AVSampleFormat sample_fmt[2]; ///< input and output sample format - unsigned sample_size[2]; ///< size of one sample in sample_fmt - short *buffer[2]; ///< buffers used for conversion to S16 - unsigned buffer_size[2]; ///< sizes of allocated buffers -}; - -/* n1: number of samples */ -static void stereo_to_mono(short *output, short *input, int n1) -{ - short *p, *q; - int n = n1; - - p = input; - q = output; - while (n >= 4) { - q[0] = (p[0] + p[1]) >> 1; - q[1] = (p[2] + p[3]) >> 1; - q[2] = (p[4] + p[5]) >> 1; - q[3] = (p[6] + p[7]) >> 1; - q += 4; - p += 8; - n -= 4; - } - while (n > 0) { - q[0] = (p[0] + p[1]) >> 1; - q++; - p += 2; - n--; - } -} - -/* n1: number of samples */ -static void mono_to_stereo(short *output, short *input, int n1) -{ - short *p, *q; - int n = n1; - int v; - - p = input; - q = output; - while (n >= 4) { - v = p[0]; q[0] = v; q[1] = v; - v = p[1]; q[2] = v; q[3] = v; - v = p[2]; q[4] = v; q[5] = v; - v = p[3]; q[6] = v; q[7] = v; - q += 8; - p += 4; - n -= 4; - } - while (n > 0) { - v = p[0]; q[0] = v; q[1] = v; - q += 2; - p += 1; - n--; - } -} - -/* -5.1 to stereo input: [fl, fr, c, lfe, rl, rr] -- Left = front_left + rear_gain * rear_left + center_gain * center -- Right = front_right + rear_gain * rear_right + center_gain * center -Where rear_gain is usually around 0.5-1.0 and - center_gain is almost always 0.7 (-3 dB) -*/ -static void surround_to_stereo(short **output, short *input, int channels, int samples) -{ - int i; - short l, r; - - for (i = 0; i < samples; i++) { - int fl,fr,c,rl,rr; - fl = input[0]; - fr = input[1]; - c = input[2]; - // lfe = input[3]; - rl = input[4]; - rr = input[5]; - - l = av_clip_int16(fl + (0.5 * rl) + (0.7 * c)); - r = av_clip_int16(fr + (0.5 * rr) + (0.7 * c)); - - /* output l & r. */ - *output[0]++ = l; - *output[1]++ = r; - - /* increment input. */ - input += channels; - } -} - -static void deinterleave(short **output, short *input, int channels, int samples) -{ - int i, j; - - for (i = 0; i < samples; i++) { - for (j = 0; j < channels; j++) { - *output[j]++ = *input++; - } - } -} - -static void interleave(short *output, short **input, int channels, int samples) -{ - int i, j; - - for (i = 0; i < samples; i++) { - for (j = 0; j < channels; j++) { - *output++ = *input[j]++; - } - } -} - -static void ac3_5p1_mux(short *output, short *input1, short *input2, int n) -{ - int i; - short l, r; - - for (i = 0; i < n; i++) { - l = *input1++; - r = *input2++; - *output++ = l; /* left */ - *output++ = (l / 2) + (r / 2); /* center */ - *output++ = r; /* right */ - *output++ = 0; /* left surround */ - *output++ = 0; /* right surroud */ - *output++ = 0; /* low freq */ - } -} - -#define SUPPORT_RESAMPLE(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8) \ - ch8<<7 | ch7<<6 | ch6<<5 | ch5<<4 | ch4<<3 | ch3<<2 | ch2<<1 | ch1<<0 - -static const uint8_t supported_resampling[MAX_CHANNELS] = { - // output ch: 1 2 3 4 5 6 7 8 - SUPPORT_RESAMPLE(1, 1, 0, 0, 0, 0, 0, 0), // 1 input channel - SUPPORT_RESAMPLE(1, 1, 0, 0, 0, 1, 0, 0), // 2 input channels - SUPPORT_RESAMPLE(0, 0, 1, 0, 0, 0, 0, 0), // 3 input channels - SUPPORT_RESAMPLE(0, 0, 0, 1, 0, 0, 0, 0), // 4 input channels - SUPPORT_RESAMPLE(0, 0, 0, 0, 1, 0, 0, 0), // 5 input channels - SUPPORT_RESAMPLE(0, 1, 0, 0, 0, 1, 0, 0), // 6 input channels - SUPPORT_RESAMPLE(0, 0, 0, 0, 0, 0, 1, 0), // 7 input channels - SUPPORT_RESAMPLE(0, 0, 0, 0, 0, 0, 0, 1), // 8 input channels -}; - -ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate, - enum AVSampleFormat sample_fmt_out, - enum AVSampleFormat sample_fmt_in, - int filter_length, int log2_phase_count, - int linear, double cutoff) -{ - ReSampleContext *s; - - if (input_channels > MAX_CHANNELS) { - av_log(NULL, AV_LOG_ERROR, - "Resampling with input channels greater than %d is unsupported.\n", - MAX_CHANNELS); - return NULL; - } - if (!(supported_resampling[input_channels-1] & (1<<(output_channels-1)))) { - int i; - av_log(NULL, AV_LOG_ERROR, "Unsupported audio resampling. Allowed " - "output channels for %d input channel%s", input_channels, - input_channels > 1 ? "s:" : ":"); - for (i = 0; i < MAX_CHANNELS; i++) - if (supported_resampling[input_channels-1] & (1<ratio = (float)output_rate / (float)input_rate; - - s->input_channels = input_channels; - s->output_channels = output_channels; - - s->filter_channels = s->input_channels; - if (s->output_channels < s->filter_channels) - s->filter_channels = s->output_channels; - - s->sample_fmt[0] = sample_fmt_in; - s->sample_fmt[1] = sample_fmt_out; - s->sample_size[0] = av_get_bytes_per_sample(s->sample_fmt[0]); - s->sample_size[1] = av_get_bytes_per_sample(s->sample_fmt[1]); - - if (s->sample_fmt[0] != AV_SAMPLE_FMT_S16) { - if (!(s->convert_ctx[0] = av_audio_convert_alloc(AV_SAMPLE_FMT_S16, 1, - s->sample_fmt[0], 1, NULL, 0))) { - av_log(s, AV_LOG_ERROR, - "Cannot convert %s sample format to s16 sample format\n", - av_get_sample_fmt_name(s->sample_fmt[0])); - av_free(s); - return NULL; - } - } - - if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) { - if (!(s->convert_ctx[1] = av_audio_convert_alloc(s->sample_fmt[1], 1, - AV_SAMPLE_FMT_S16, 1, NULL, 0))) { - av_log(s, AV_LOG_ERROR, - "Cannot convert s16 sample format to %s sample format\n", - av_get_sample_fmt_name(s->sample_fmt[1])); - av_audio_convert_free(s->convert_ctx[0]); - av_free(s); - return NULL; - } - } - - s->resample_context = av_resample_init(output_rate, input_rate, - filter_length, log2_phase_count, - linear, cutoff); - - *(const AVClass**)s->resample_context = &audioresample_context_class; - - return s; -} - -/* resample audio. 'nb_samples' is the number of input samples */ -/* XXX: optimize it ! */ -int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples) -{ - int i, nb_samples1; - short *bufin[MAX_CHANNELS]; - short *bufout[MAX_CHANNELS]; - short *buftmp2[MAX_CHANNELS], *buftmp3[MAX_CHANNELS]; - short *output_bak = NULL; - int lenout; - - if (s->sample_fmt[0] != AV_SAMPLE_FMT_S16) { - int istride[1] = { s->sample_size[0] }; - int ostride[1] = { 2 }; - const void *ibuf[1] = { input }; - void *obuf[1]; - unsigned input_size = nb_samples * s->input_channels * 2; - - if (!s->buffer_size[0] || s->buffer_size[0] < input_size) { - av_free(s->buffer[0]); - s->buffer_size[0] = input_size; - s->buffer[0] = av_malloc(s->buffer_size[0]); - if (!s->buffer[0]) { - av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n"); - return 0; - } - } - - obuf[0] = s->buffer[0]; - - if (av_audio_convert(s->convert_ctx[0], obuf, ostride, - ibuf, istride, nb_samples * s->input_channels) < 0) { - av_log(s->resample_context, AV_LOG_ERROR, - "Audio sample format conversion failed\n"); - return 0; - } - - input = s->buffer[0]; - } - - lenout= 2*s->output_channels*nb_samples * s->ratio + 16; - - if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) { - int out_size = lenout * av_get_bytes_per_sample(s->sample_fmt[1]) * - s->output_channels; - output_bak = output; - - if (!s->buffer_size[1] || s->buffer_size[1] < out_size) { - av_free(s->buffer[1]); - s->buffer_size[1] = out_size; - s->buffer[1] = av_malloc(s->buffer_size[1]); - if (!s->buffer[1]) { - av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n"); - return 0; - } - } - - output = s->buffer[1]; - } - - /* XXX: move those malloc to resample init code */ - for (i = 0; i < s->filter_channels; i++) { - bufin[i] = av_malloc_array((nb_samples + s->temp_len), sizeof(short)); - bufout[i] = av_malloc_array(lenout, sizeof(short)); - - if (!bufin[i] || !bufout[i]) { - av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n"); - nb_samples1 = 0; - goto fail; - } - - memcpy(bufin[i], s->temp[i], s->temp_len * sizeof(short)); - buftmp2[i] = bufin[i] + s->temp_len; - } - - if (s->input_channels == 2 && s->output_channels == 1) { - buftmp3[0] = output; - stereo_to_mono(buftmp2[0], input, nb_samples); - } else if (s->output_channels >= 2 && s->input_channels == 1) { - buftmp3[0] = bufout[0]; - memcpy(buftmp2[0], input, nb_samples * sizeof(short)); - } else if (s->input_channels == 6 && s->output_channels ==2) { - buftmp3[0] = bufout[0]; - buftmp3[1] = bufout[1]; - surround_to_stereo(buftmp2, input, s->input_channels, nb_samples); - } else if (s->output_channels >= s->input_channels && s->input_channels >= 2) { - for (i = 0; i < s->input_channels; i++) { - buftmp3[i] = bufout[i]; - } - deinterleave(buftmp2, input, s->input_channels, nb_samples); - } else { - buftmp3[0] = output; - memcpy(buftmp2[0], input, nb_samples * sizeof(short)); - } - - nb_samples += s->temp_len; - - /* resample each channel */ - nb_samples1 = 0; /* avoid warning */ - for (i = 0; i < s->filter_channels; i++) { - int consumed; - int is_last = i + 1 == s->filter_channels; - - nb_samples1 = av_resample(s->resample_context, buftmp3[i], bufin[i], - &consumed, nb_samples, lenout, is_last); - s->temp_len = nb_samples - consumed; - s->temp[i] = av_realloc_array(s->temp[i], s->temp_len, sizeof(short)); - memcpy(s->temp[i], bufin[i] + consumed, s->temp_len * sizeof(short)); - } - - if (s->output_channels == 2 && s->input_channels == 1) { - mono_to_stereo(output, buftmp3[0], nb_samples1); - } else if (s->output_channels == 6 && s->input_channels == 2) { - ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1); - } else if ((s->output_channels == s->input_channels && s->input_channels >= 2) || - (s->output_channels == 2 && s->input_channels == 6)) { - interleave(output, buftmp3, s->output_channels, nb_samples1); - } - - if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) { - int istride[1] = { 2 }; - int ostride[1] = { s->sample_size[1] }; - const void *ibuf[1] = { output }; - void *obuf[1] = { output_bak }; - - if (av_audio_convert(s->convert_ctx[1], obuf, ostride, - ibuf, istride, nb_samples1 * s->output_channels) < 0) { - av_log(s->resample_context, AV_LOG_ERROR, - "Audio sample format conversion failed\n"); - return 0; - } - } - -fail: - for (i = 0; i < s->filter_channels; i++) { - av_free(bufin[i]); - av_free(bufout[i]); - } - - return nb_samples1; -} - -void audio_resample_close(ReSampleContext *s) -{ - int i; - av_resample_close(s->resample_context); - for (i = 0; i < s->filter_channels; i++) - av_freep(&s->temp[i]); - av_freep(&s->buffer[0]); - av_freep(&s->buffer[1]); - av_audio_convert_free(s->convert_ctx[0]); - av_audio_convert_free(s->convert_ctx[1]); - av_free(s); -} - -FF_ENABLE_DEPRECATION_WARNINGS -#endif diff --git a/libavcodec/resample2.c b/libavcodec/resample2.c deleted file mode 100644 index 56ae9f722..000000000 --- a/libavcodec/resample2.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * audio resampling - * 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 - * audio resampling - * @author Michael Niedermayer - */ - -#include "libavutil/avassert.h" -#include "avcodec.h" -#include "libavutil/common.h" - -#if FF_API_AVCODEC_RESAMPLE - -#ifndef CONFIG_RESAMPLE_HP -#define FILTER_SHIFT 15 - -typedef int16_t FELEM; -typedef int32_t FELEM2; -typedef int64_t FELEML; -#define FELEM_MAX INT16_MAX -#define FELEM_MIN INT16_MIN -#define WINDOW_TYPE 9 -#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE) -#define FILTER_SHIFT 30 - -#define FELEM int32_t -#define FELEM2 int64_t -#define FELEML int64_t -#define FELEM_MAX INT32_MAX -#define FELEM_MIN INT32_MIN -#define WINDOW_TYPE 12 -#else -#define FILTER_SHIFT 0 - -typedef double FELEM; -typedef double FELEM2; -typedef double FELEML; -#define WINDOW_TYPE 24 -#endif - - -typedef struct AVResampleContext{ - const AVClass *av_class; - FELEM *filter_bank; - int filter_length; - int ideal_dst_incr; - int dst_incr; - int index; - int frac; - int src_incr; - int compensation_distance; - int phase_shift; - int phase_mask; - int linear; -}AVResampleContext; - -/** - * 0th order modified bessel function of the first kind. - */ -static double bessel(double x){ - double v=1; - double lastv=0; - double t=1; - int i; - - x= x*x/4; - for(i=1; v != lastv; i++){ - lastv=v; - t *= x/(i*i); - v += t; - } - return v; -} - -/** - * Build a polyphase filterbank. - * @param factor resampling factor - * @param scale wanted sum of coefficients for each filter - * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16 - * @return 0 on success, negative on error - */ -static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ - int ph, i; - double x, y, w; - double *tab = av_malloc_array(tap_count, sizeof(*tab)); - const int center= (tap_count-1)/2; - - if (!tab) - return AVERROR(ENOMEM); - - /* if upsampling, only need to interpolate, no filter */ - if (factor > 1.0) - factor = 1.0; - - for(ph=0;phphase_shift= phase_shift; - c->phase_mask= phase_count-1; - c->linear= linear; - - c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); - c->filter_bank= av_mallocz_array(c->filter_length, (phase_count+1)*sizeof(FELEM)); - if (!c->filter_bank) - goto error; - if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM)); - c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1]; - - if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2)) - goto error; - c->ideal_dst_incr= c->dst_incr; - - c->index= -phase_count*((c->filter_length-1)/2); - - return c; -error: - av_free(c->filter_bank); - av_free(c); - return NULL; -} - -void av_resample_close(AVResampleContext *c){ - av_freep(&c->filter_bank); - av_freep(&c); -} - -void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){ -// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr; - c->compensation_distance= compensation_distance; - c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; -} - -int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){ - int dst_index, i; - int index= c->index; - int frac= c->frac; - int dst_incr_frac= c->dst_incr % c->src_incr; - int dst_incr= c->dst_incr / c->src_incr; - int compensation_distance= c->compensation_distance; - - if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){ - int64_t index2= ((int64_t)index)<<32; - int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; - dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr); - - for(dst_index=0; dst_index < dst_size; dst_index++){ - dst[dst_index] = src[index2>>32]; - index2 += incr; - } - index += dst_index * dst_incr; - index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr; - frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; - }else{ - for(dst_index=0; dst_index < dst_size; dst_index++){ - FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask); - int sample_index= index >> c->phase_shift; - FELEM2 val=0; - - if(sample_index < 0){ - for(i=0; ifilter_length; i++) - val += src[FFABS(sample_index + i) % src_size] * filter[i]; - }else if(sample_index + c->filter_length > src_size){ - break; - }else if(c->linear){ - FELEM2 v2=0; - for(i=0; ifilter_length; i++){ - val += src[sample_index + i] * (FELEM2)filter[i]; - v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length]; - } - val+=(v2-val)*(FELEML)frac / c->src_incr; - }else{ - for(i=0; ifilter_length; i++){ - val += src[sample_index + i] * (FELEM2)filter[i]; - } - } - -#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE - dst[dst_index] = av_clip_int16(lrintf(val)); -#else - val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; - dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val; -#endif - - frac += dst_incr_frac; - index += dst_incr; - if(frac >= c->src_incr){ - frac -= c->src_incr; - index++; - } - - if(dst_index + 1 == compensation_distance){ - compensation_distance= 0; - dst_incr_frac= c->ideal_dst_incr % c->src_incr; - dst_incr= c->ideal_dst_incr / c->src_incr; - } - } - } - *consumed= FFMAX(index, 0) >> c->phase_shift; - if(index>=0) index &= c->phase_mask; - - if(compensation_distance){ - compensation_distance -= dst_index; - av_assert2(compensation_distance > 0); - } - if(update_ctx){ - c->frac= frac; - c->index= index; - c->dst_incr= dst_incr_frac + c->src_incr*dst_incr; - c->compensation_distance= compensation_distance; - } - - return dst_index; -} - -#endif diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c index bdf4dc420..143d05bd5 100644 --- a/libavcodec/rkmppdec.c +++ b/libavcodec/rkmppdec.c @@ -28,6 +28,7 @@ #include "avcodec.h" #include "decode.h" +#include "hwaccel.h" #include "internal.h" #include "libavutil/buffer.h" #include "libavutil/common.h" @@ -39,13 +40,13 @@ #define RECEIVE_FRAME_TIMEOUT 100 #define FRAMEGROUP_MAX_FRAMES 16 +#define INPUT_MAX_PACKETS 4 typedef struct { MppCtx ctx; MppApi *mpi; MppBufferGroup frame_group; - char first_frame; char first_packet; char eos_reached; @@ -327,28 +328,14 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) MppBuffer buffer = NULL; AVDRMFrameDescriptor *desc = NULL; AVDRMLayerDescriptor *layer = NULL; - int retrycount = 0; int mode; MppFrameFormat mppformat; uint32_t drmformat; - // on start of decoding, MPP can return -1, which is supposed to be expected - // this is due to some internal MPP init which is not completed, that will - // only happen in the first few frames queries, but should not be interpreted - // as an error, Therefore we need to retry a couple times when we get -1 - // in order to let it time to complete it's init, then we sleep a bit between retries. -retry_get_frame: ret = decoder->mpi->decode_get_frame(decoder->ctx, &mppframe); - if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT && !decoder->first_frame) { - if (retrycount < 5) { - av_log(avctx, AV_LOG_DEBUG, "Failed to get a frame, retrying (code = %d, retrycount = %d)\n", ret, retrycount); - usleep(10000); - retrycount++; - goto retry_get_frame; - } else { - av_log(avctx, AV_LOG_ERROR, "Failed to get a frame from MPP (code = %d)\n", ret); - goto fail; - } + if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) { + av_log(avctx, AV_LOG_ERROR, "Failed to get a frame from MPP (code = %d)\n", ret); + goto fail; } if (mppframe) { @@ -364,7 +351,6 @@ retry_get_frame: avctx->height = mpp_frame_get_height(mppframe); decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); - decoder->first_frame = 1; av_buffer_unref(&decoder->frames_ref); @@ -478,7 +464,6 @@ retry_get_frame: goto fail; } - decoder->first_frame = 0; return 0; } else { av_log(avctx, AV_LOG_ERROR, "Failed to retrieve the frame buffer, frame is dropped (code = %d)\n", ret); @@ -514,16 +499,17 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; int ret = MPP_NOK; AVPacket pkt = {0}; - RK_S32 freeslots; + RK_S32 usedslots, freeslots; if (!decoder->eos_reached) { // we get the available slots in decoder - ret = decoder->mpi->control(decoder->ctx, MPP_DEC_GET_FREE_PACKET_SLOT_COUNT, &freeslots); + ret = decoder->mpi->control(decoder->ctx, MPP_DEC_GET_STREAM_COUNT, &usedslots); if (ret != MPP_OK) { - av_log(avctx, AV_LOG_ERROR, "Failed to get decoder free slots (code = %d).\n", ret); + av_log(avctx, AV_LOG_ERROR, "Failed to get decoder used slots (code = %d).\n", ret); return ret; } + freeslots = INPUT_MAX_PACKETS - usedslots; if (freeslots > 0) { ret = ff_decode_get_packet(avctx, &pkt); if (ret < 0 && ret != AVERROR_EOF) { @@ -540,7 +526,7 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) } // make sure we keep decoder full - if (freeslots > 1 && decoder->first_frame) + if (freeslots > 1) return AVERROR(EAGAIN); } @@ -557,12 +543,15 @@ static void rkmpp_flush(AVCodecContext *avctx) ret = decoder->mpi->reset(decoder->ctx); if (ret == MPP_OK) { - decoder->first_frame = 1; decoder->first_packet = 1; } else av_log(avctx, AV_LOG_ERROR, "Failed to reset MPI (code = %d)\n", ret); } +static const AVCodecHWConfigInternal *rkmpp_hw_configs[] = { + HW_CONFIG_INTERNAL(DRM_PRIME), + NULL +}; #define RKMPP_DEC_CLASS(NAME) \ static const AVClass rkmpp_##NAME##_dec_class = { \ @@ -583,11 +572,12 @@ static void rkmpp_flush(AVCodecContext *avctx) .receive_frame = rkmpp_receive_frame, \ .flush = rkmpp_flush, \ .priv_class = &rkmpp_##NAME##_dec_class, \ - .capabilities = AV_CODEC_CAP_DELAY, \ - .caps_internal = AV_CODEC_CAP_AVOID_PROBING, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ AV_PIX_FMT_NONE}, \ + .hw_configs = rkmpp_hw_configs, \ .bsfs = BSFS, \ + .wrapper_name = "rkmpp", \ }; RKMPP_DEC(h264, AV_CODEC_ID_H264, "h264_mp4toannexb") diff --git a/libavcodec/s302m.c b/libavcodec/s302m.c index 4350d97f0..584b58e28 100644 --- a/libavcodec/s302m.c +++ b/libavcodec/s302m.c @@ -212,10 +212,10 @@ static const AVOption s302m_options[] = { }; static const AVClass s302m_class = { - "SMPTE 302M Decoder", - av_default_item_name, - s302m_options, - LIBAVUTIL_VERSION_INT, + .class_name = "SMPTE 302M Decoder", + .item_name = av_default_item_name, + .option = s302m_options, + .version = LIBAVUTIL_VERSION_INT, }; AVCodec ff_s302m_decoder = { diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c index 262042475..e32f238c6 100644 --- a/libavcodec/samidec.c +++ b/libavcodec/samidec.c @@ -48,6 +48,9 @@ static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src) AVBPrint *dst_content = &sami->encoded_content; AVBPrint *dst_source = &sami->encoded_source; + if (!dupsrc) + return AVERROR(ENOMEM); + av_bprint_clear(&sami->encoded_content); av_bprint_clear(&sami->content); av_bprint_clear(&sami->encoded_source); @@ -135,9 +138,12 @@ static int sami_decode_frame(AVCodecContext *avctx, const char *ptr = avpkt->data; SAMIContext *sami = avctx->priv_data; - if (ptr && avpkt->size > 0 && !sami_paragraph_to_ass(avctx, ptr)) { + if (ptr && avpkt->size > 0) { + int ret = sami_paragraph_to_ass(avctx, ptr); + if (ret < 0) + return ret; // TODO: pass escaped sami->encoded_source.str as source - int ret = ff_ass_add_rect(sub, sami->full.str, sami->readorder++, 0, NULL, NULL); + ret = ff_ass_add_rect(sub, sami->full.str, sami->readorder++, 0, NULL, NULL); if (ret < 0) return ret; } diff --git a/libavcodec/sbrdsp_fixed.c b/libavcodec/sbrdsp_fixed.c index 896b2d75c..57d98da97 100644 --- a/libavcodec/sbrdsp_fixed.c +++ b/libavcodec/sbrdsp_fixed.c @@ -133,7 +133,7 @@ static av_always_inline SoftFloat autocorr_calc(int64_t accu) round = 1U << (nz-1); mant = (int)((accu + round) >> nz); - mant = (mant + 0x40)>>7; + mant = (mant + 0x40LL)>>7; mant *= 64; expo = nz + 15; return av_int2sf(mant, 30 - expo); @@ -244,12 +244,14 @@ static void sbr_hf_g_filt_c(int (*Y)[2], const int (*X_high)[40][2], int64_t accu; for (m = 0; m < m_max; m++) { - 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)); + 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)); + 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)); + } } } diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c index 2d20be9c1..61e316916 100644 --- a/libavcodec/smacker.c +++ b/libavcodec/smacker.c @@ -43,6 +43,8 @@ #define SMKTREE_BITS 9 #define SMK_NODE 0x80000000 +#define SMKTREE_DECODE_MAX_RECURSION 32 +#define SMKTREE_DECODE_BIG_MAX_RECURSION 500 typedef struct SmackVContext { AVCodecContext *avctx; @@ -95,10 +97,11 @@ enum SmkBlockTypes { */ static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length) { - if(length > 32 || length > 3*SMKTREE_BITS) { - av_log(NULL, AV_LOG_ERROR, "length too long\n"); + if (length > SMKTREE_DECODE_MAX_RECURSION || length > 3 * SMKTREE_BITS) { + av_log(NULL, AV_LOG_ERROR, "Maximum tree recursion level exceeded.\n"); return AVERROR_INVALIDDATA; } + if(!get_bits1(gb)){ //Leaf if(hc->current >= hc->length){ av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n"); @@ -129,12 +132,15 @@ static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t pref /** * Decode header tree */ -static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, DBCtx *ctx, int length) +static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, + DBCtx *ctx, int length) { - if(length > 500) { // Larger length can cause segmentation faults due to too deep recursion. - av_log(NULL, AV_LOG_ERROR, "length too long\n"); + // Larger length can cause segmentation faults due to too deep recursion. + if (length > SMKTREE_DECODE_BIG_MAX_RECURSION) { + av_log(NULL, AV_LOG_ERROR, "Maximum bigtree recursion level exceeded.\n"); return AVERROR_INVALIDDATA; } + if (hc->current + 1 >= hc->length) { av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n"); return AVERROR_INVALIDDATA; @@ -279,8 +285,9 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int goto error; } - if (smacker_decode_bigtree(gb, &huff, &ctx, 0) < 0) - err = -1; + res = smacker_decode_bigtree(gb, &huff, &ctx, 0); + if (res < 0) + err = res; skip_bits1(gb); if(ctx.last[0] == -1) ctx.last[0] = huff.current++; if(ctx.last[1] == -1) ctx.last[1] = huff.current++; @@ -600,7 +607,7 @@ static av_cold int smka_decode_init(AVCodecContext *avctx) { if (avctx->channels < 1 || avctx->channels > 2) { av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } avctx->channel_layout = (avctx->channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; avctx->sample_fmt = avctx->bits_per_coded_sample == 8 ? AV_SAMPLE_FMT_U8 : AV_SAMPLE_FMT_S16; @@ -630,7 +637,7 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, if (buf_size <= 4) { av_log(avctx, AV_LOG_ERROR, "packet is too small\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } unp_size = AV_RL32(buf); @@ -652,18 +659,19 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, bits = get_bits1(&gb); if (stereo ^ (avctx->channels != 1)) { av_log(avctx, AV_LOG_ERROR, "channels mismatch\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } if (bits == (avctx->sample_fmt == AV_SAMPLE_FMT_U8)) { av_log(avctx, AV_LOG_ERROR, "sample format mismatch\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } /* get output buffer */ frame->nb_samples = unp_size / (avctx->channels * (bits + 1)); if (unp_size % (avctx->channels * (bits + 1))) { - av_log(avctx, AV_LOG_ERROR, "unp_size %d is odd\n", unp_size); - return AVERROR(EINVAL); + av_log(avctx, AV_LOG_ERROR, + "The buffer does not contain an integer number of samples\n"); + return AVERROR_INVALIDDATA; } if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index 13668c210..a9bdb8da5 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -183,13 +183,22 @@ static int decode_q_branch(SnowContext *s, int level, int x, int y){ int my_context= av_log2(2*FFABS(left->my - top->my)) + 0*av_log2(2*FFABS(tr->my - top->my)); type= get_rac(&s->c, &s->block_state[1 + left->type + top->type]) ? BLOCK_INTRA : 0; - if(type){ + int ld, cbd, crd; pred_mv(s, &mx, &my, 0, left, top, tr); - l += get_symbol(&s->c, &s->block_state[32], 1); + ld = get_symbol(&s->c, &s->block_state[32], 1); + if (ld < -255 || ld > 255) { + return AVERROR_INVALIDDATA; + } + l += ld; if (s->nb_planes > 2) { - cb+= get_symbol(&s->c, &s->block_state[64], 1); - cr+= get_symbol(&s->c, &s->block_state[96], 1); + cbd = get_symbol(&s->c, &s->block_state[64], 1); + crd = get_symbol(&s->c, &s->block_state[96], 1); + if (cbd < -255 || cbd > 255 || crd < -255 || crd > 255) { + return AVERROR_INVALIDDATA; + } + cb += cbd; + cr += crd; } }else{ if(s->ref_frames > 1) @@ -374,7 +383,7 @@ static int decode_header(SnowContext *s){ } } - s->spatial_decomposition_type+= get_symbol(&s->c, s->header_state, 1); + s->spatial_decomposition_type+= (unsigned)get_symbol(&s->c, s->header_state, 1); if(s->spatial_decomposition_type > 1U){ av_log(s->avctx, AV_LOG_ERROR, "spatial_decomposition_type %d not supported\n", s->spatial_decomposition_type); return AVERROR_INVALIDDATA; @@ -390,10 +399,10 @@ static int decode_header(SnowContext *s){ } - s->qlog += get_symbol(&s->c, s->header_state, 1); - s->mv_scale += get_symbol(&s->c, s->header_state, 1); - s->qbias += get_symbol(&s->c, s->header_state, 1); - s->block_max_depth+= get_symbol(&s->c, s->header_state, 1); + s->qlog += (unsigned)get_symbol(&s->c, s->header_state, 1); + s->mv_scale += (unsigned)get_symbol(&s->c, s->header_state, 1); + s->qbias += (unsigned)get_symbol(&s->c, s->header_state, 1); + s->block_max_depth+= (unsigned)get_symbol(&s->c, s->header_state, 1); if(s->block_max_depth > 1 || s->block_max_depth < 0 || s->mv_scale > 256U){ av_log(s->avctx, AV_LOG_ERROR, "block_max_depth= %d is too large\n", s->block_max_depth); s->block_max_depth= 0; @@ -428,6 +437,8 @@ static int decode_blocks(SnowContext *s){ for(y=0; yc.bytestream >= s->c.bytestream_end) + return AVERROR_INVALIDDATA; if ((res = decode_q_branch(s, 0, x, y)) < 0) return res; } diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 0d800b9f4..4fec37759 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -22,6 +22,7 @@ #include "libavutil/libm.h" #include "libavutil/log.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "internal.h" #include "snow_dwt.h" @@ -52,12 +53,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_ERROR, "The 9/7 wavelet is incompatible with lossless mode.\n"); return AVERROR(EINVAL); } -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->me_method == ME_ITER) - s->motion_est = FF_ME_ITER; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->spatial_decomposition_type= s->pred; //FIXME add decorrelator type r transform_type @@ -133,7 +128,13 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_ERROR, "pixel format not supported\n"); return AVERROR_PATCHWELCOME; } - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); + + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, + &s->chroma_v_shift); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "pixel format invalid or unknown\n"); + return ret; + } ff_set_cmp(&s->mecc, s->mecc.me_cmp, s->avctx->me_cmp); ff_set_cmp(&s->mecc, s->mecc.me_sub_cmp, s->avctx->me_sub_cmp); @@ -1622,11 +1623,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->lambda = 0; }//else keep previous frame's qlog until after motion estimation - if (s->current_picture->data[0] -#if FF_API_EMU_EDGE - && !(s->avctx->flags&CODEC_FLAG_EMU_EDGE) -#endif - ) { + if (s->current_picture->data[0]) { int w = s->avctx->width; int h = s->avctx->height; @@ -1679,11 +1676,6 @@ FF_ENABLE_DEPRECATION_WARNINGS s->m.b8_stride= 2*s->m.mb_width+1; s->m.f_code=1; s->m.pict_type = pic->pict_type; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - s->m.me_method= s->avctx->me_method; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->m.motion_est= s->motion_est; s->m.me.scene_change_score=0; s->m.me.dia_size = avctx->dia_size; diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c index d78ede72c..80a8af1ef 100644 --- a/libavcodec/svq1enc.c +++ b/libavcodec/svq1enc.c @@ -283,19 +283,6 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, s->m.b8_stride = 2 * s->m.mb_width + 1; s->m.f_code = 1; s->m.pict_type = s->pict_type; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - s->m.me_method = s->avctx->me_method; - if (s->motion_est == FF_ME_EPZS) { - if (s->avctx->me_method == ME_ZERO) - s->motion_est = FF_ME_ZERO; - else if (s->avctx->me_method == ME_EPZS) - s->motion_est = FF_ME_EPZS; - else if (s->avctx->me_method == ME_X1) - s->motion_est = FF_ME_XONE; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->m.motion_est = s->motion_est; s->m.me.scene_change_score = 0; // s->m.out_format = FMT_H263; diff --git a/libavcodec/tak.c b/libavcodec/tak.c index d2670e00f..8aa956b66 100644 --- a/libavcodec/tak.c +++ b/libavcodec/tak.c @@ -90,7 +90,7 @@ int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size) return 0; } -void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s) +void ff_tak_parse_streaminfo(TAKStreamInfo *s, GetBitContext *gb) { uint64_t channel_mask = 0; int frame_type, i; @@ -125,6 +125,19 @@ void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s) s->frame_samples = tak_get_nb_samples(s->sample_rate, frame_type); } +int avpriv_tak_parse_streaminfo(TAKStreamInfo *s, const uint8_t *buf, int size) +{ + GetBitContext gb; + int ret = init_get_bits8(&gb, buf, size); + + if (ret < 0) + return AVERROR_INVALIDDATA; + + ff_tak_parse_streaminfo(s, &gb); + + return 0; +} + int ff_tak_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, TAKStreamInfo *ti, int log_level_offset) { @@ -144,7 +157,7 @@ int ff_tak_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, } if (ti->flags & TAK_FRAME_FLAG_HAS_INFO) { - avpriv_tak_parse_streaminfo(gb, ti); + ff_tak_parse_streaminfo(ti, gb); if (get_bits(gb, 6)) skip_bits(gb, 25); diff --git a/libavcodec/tak.h b/libavcodec/tak.h index 4fa123909..dc45a8c07 100644 --- a/libavcodec/tak.h +++ b/libavcodec/tak.h @@ -143,10 +143,14 @@ int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size); /** * Parse the Streaminfo metadata block. - * @param[in] gb pointer to GetBitContext * @param[out] s storage for parsed information + * @param[in] buf input buffer + * @param[in] size size of input buffer in bytes + * @return non-zero on error, 0 if OK */ -void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s); +int avpriv_tak_parse_streaminfo(TAKStreamInfo *s, const uint8_t *buf, int size); + +void ff_tak_parse_streaminfo(TAKStreamInfo *s, GetBitContext *gb); /** * Validate and decode a frame header. diff --git a/libavcodec/tests/.gitignore b/libavcodec/tests/.gitignore new file mode 100644 index 000000000..350fb2990 --- /dev/null +++ b/libavcodec/tests/.gitignore @@ -0,0 +1,21 @@ +/avfft +/avpacket +/cabac +/celp_math +/dct +/fft +/fft-fixed +/fft-fixed32 +/golomb +/htmlsubtitles +/iirfilter +/imgconvert +/jpeg2000dwt +/mathops +/mjpegenc_huffman +/motion +/mpeg12framerate +/options +/rangecoder +/snowenc +/utils diff --git a/libavcodec/tests/mpeg12framerate.c b/libavcodec/tests/mpeg12framerate.c new file mode 100644 index 000000000..595bdb278 --- /dev/null +++ b/libavcodec/tests/mpeg12framerate.c @@ -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 + */ + +#include "libavcodec/mpeg12.h" +#include "libavcodec/mpeg12data.h" + +int main(void) +{ + int i; + +#define TEST_MATCH(frame_rate, code, ext_n, ext_d) do { \ + AVRational fr = frame_rate; \ + int c, n, d; \ + ff_mpeg12_find_best_frame_rate(fr, &c, &n, &d, 0); \ + if (c != code || n != ext_n || d != ext_d) { \ + av_log(NULL, AV_LOG_ERROR, "Failed to match %d/%d: " \ + "code = %d, ext_n = %d, ext_d = %d.\n", \ + fr.num, fr.den, c, n, d); \ + return 1; \ + } \ + } while (0) +#define TEST_EXACT(frn, frd) do { \ + AVRational fr = (AVRational) { frn, frd }; \ + int c, n, d; \ + ff_mpeg12_find_best_frame_rate(fr, &c, &n, &d, 0); \ + if (av_cmp_q(fr, av_mul_q(ff_mpeg12_frame_rate_tab[c], \ + (AVRational) { n + 1, d + 1 })) != 0) { \ + av_log(NULL, AV_LOG_ERROR, "Failed to find exact %d/%d: " \ + "code = %d, ext_n = %d, ext_d = %d.\n", \ + fr.num, fr.den, c, n, d); \ + return 1; \ + } \ + } while (0) + + // Framerates in the table must be chosen exactly. + for (i = 1; i <= 8; i++) + TEST_MATCH(ff_mpeg12_frame_rate_tab[i], i, 0, 0); + + // As should the same ones with small perturbations. + // (1/1000 used here to be smaller than half the difference + // between 24 and 24000/1001.) + for (i = 1; i <= 8; i++) { + TEST_MATCH(av_sub_q(ff_mpeg12_frame_rate_tab[i], + (AVRational) { 1, 1000 }), i, 0, 0); + TEST_MATCH(av_add_q(ff_mpeg12_frame_rate_tab[i], + (AVRational) { 1, 1000 }), i, 0, 0); + } + + // Exactly constructable framerates should be exact. Note that some + // values can be made in multiple ways (e.g. 12 = 24 / 2 == 60 / 5), + // and there is no reason to favour any particular choice. + TEST_EXACT( 1, 1); + TEST_EXACT( 2, 1); + TEST_EXACT( 12, 1); + TEST_EXACT( 15000, 1001); + TEST_EXACT( 15, 1); + TEST_EXACT( 120, 1); + TEST_EXACT(120000, 1001); + TEST_EXACT( 200, 1); + TEST_EXACT( 240, 1); + + // Values higher than 240 (the highest representable, as 60 * 4 / 1) + // should be mapped to 240. + for (i = 240; i < 1000; i += 10) + TEST_MATCH(((AVRational) { i, 1 }), 8, 3, 0); + // Values lower than 24000/32032 (the lowest representable, as + // 24000/1001 * 1 / 32) should be mapped to 24000/32032. + for (i = 74; i > 0; i--) + TEST_MATCH(((AVRational) { i, 100 }), 1, 0, 31); + + return 0; +} diff --git a/libavcodec/texturedsp.c b/libavcodec/texturedsp.c index 90b1eb4f1..b7dd8baa1 100644 --- a/libavcodec/texturedsp.c +++ b/libavcodec/texturedsp.c @@ -413,7 +413,7 @@ static int dxt5ys_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) static inline void rgtc_block_internal(uint8_t *dst, ptrdiff_t stride, const uint8_t *block, - const int *color_tab) + const int *color_tab, int mono, int offset, int pix_size) { uint8_t indices[16]; int x, y; @@ -429,14 +429,20 @@ static inline void rgtc_block_internal(uint8_t *dst, ptrdiff_t stride, int i = indices[x + y * 4]; /* Interval expansion from [-1 1] or [0 1] to [0 255]. */ int c = color_tab[i]; - uint32_t pixel = RGBA(c, c, c, 255U); - AV_WL32(dst + x * 4 + y * stride, pixel); + + if (mono){ + dst [x * pix_size + y * stride + offset] = (uint8_t)c; + } + else{ + uint32_t pixel = RGBA(c, c, c, 255U); + AV_WL32(dst + x * pix_size + y * stride, pixel); + } } } } static inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, - const uint8_t *block, int sign) + const uint8_t *block, int sign, int mono, int offset, int pix_size) { int color_table[8]; int r0, r1; @@ -472,7 +478,7 @@ static inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, color_table[7] = 255; /* max range */ // bit code 111 } - rgtc_block_internal(dst, stride, block, color_table); + rgtc_block_internal(dst, stride, block, color_table, mono, offset, pix_size); } /** @@ -486,7 +492,7 @@ static inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, */ static int rgtc1s_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) { - rgtc1_block_internal(dst, stride, block, 1); + rgtc1_block_internal(dst, stride, block, 1, 0, 0, 4); return 8; } @@ -502,7 +508,39 @@ static int rgtc1s_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) */ static int rgtc1u_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) { - rgtc1_block_internal(dst, stride, block, 0); + rgtc1_block_internal(dst, stride, block, 0, 0, 0, 4); + + return 8; +} + +/** + * Decompress one block of a RGTC1 texture with unsigned components + * and overwrite the alpha component in 'dst' (RGBA data). + * + * @param dst output buffer. + * @param stride scanline in bytes. + * @param block block to decompress. + * @return how much texture data has been consumed. + */ +static int rgtc1u_alpha_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) +{ + rgtc1_block_internal(dst, stride, block, 0, 1, 3, 4); + + return 8; +} + +/** + * Decompress one block of a RGTC1 texture with unsigned components + * to Gray 8. + * + * @param dst output buffer. + * @param stride scanline in bytes. + * @param block block to decompress. + * @return how much texture data has been consumed. + */ +static int rgtc1u_gray_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) +{ + rgtc1_block_internal(dst, stride, block, 0, 1, 0, 1); return 8; } @@ -516,8 +554,8 @@ static inline void rgtc2_block_internal(uint8_t *dst, ptrdiff_t stride, int x, y; /* Decompress the two channels separately and interleave them afterwards. */ - rgtc1_block_internal(c0, 16, block, sign); - rgtc1_block_internal(c1, 16, block + 8, sign); + rgtc1_block_internal(c0, 16, block, sign, 0, 0, 4); + rgtc1_block_internal(c1, 16, block + 8, sign, 0, 0, 4); /* B is rebuilt exactly like a normal map. */ for (y = 0; y < 4; y++) { @@ -598,17 +636,19 @@ static int dxn3dc_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) av_cold void ff_texturedsp_init(TextureDSPContext *c) { - c->dxt1_block = dxt1_block; - c->dxt1a_block = dxt1a_block; - c->dxt2_block = dxt2_block; - c->dxt3_block = dxt3_block; - c->dxt4_block = dxt4_block; - c->dxt5_block = dxt5_block; - c->dxt5y_block = dxt5y_block; - c->dxt5ys_block = dxt5ys_block; - c->rgtc1s_block = rgtc1s_block; - c->rgtc1u_block = rgtc1u_block; - c->rgtc2s_block = rgtc2s_block; - c->rgtc2u_block = rgtc2u_block; - c->dxn3dc_block = dxn3dc_block; + c->dxt1_block = dxt1_block; + c->dxt1a_block = dxt1a_block; + c->dxt2_block = dxt2_block; + c->dxt3_block = dxt3_block; + c->dxt4_block = dxt4_block; + c->dxt5_block = dxt5_block; + c->dxt5y_block = dxt5y_block; + c->dxt5ys_block = dxt5ys_block; + c->rgtc1s_block = rgtc1s_block; + c->rgtc1u_block = rgtc1u_block; + c->rgtc1u_gray_block = rgtc1u_gray_block; + c->rgtc1u_alpha_block = rgtc1u_alpha_block; + c->rgtc2s_block = rgtc2s_block; + c->rgtc2u_block = rgtc2u_block; + c->dxn3dc_block = dxn3dc_block; } diff --git a/libavcodec/texturedsp.h b/libavcodec/texturedsp.h index 26f3b6473..90ceb2b6a 100644 --- a/libavcodec/texturedsp.h +++ b/libavcodec/texturedsp.h @@ -43,19 +43,21 @@ #define TEXTURE_BLOCK_H 4 typedef struct TextureDSPContext { - int (*dxt1_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt1a_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt2_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt3_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt4_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt5_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt5y_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt5ys_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc1s_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc1u_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc2s_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc2u_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxn3dc_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt1_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt1a_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt2_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt3_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt4_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt5_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt5y_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt5ys_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1s_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1u_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1u_gray_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1u_alpha_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc2s_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc2u_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxn3dc_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); } TextureDSPContext; void ff_texturedsp_init(TextureDSPContext *c); diff --git a/libavcodec/texturedspenc.c b/libavcodec/texturedspenc.c index 8b2863033..3d68e0cf3 100644 --- a/libavcodec/texturedspenc.c +++ b/libavcodec/texturedspenc.c @@ -647,9 +647,26 @@ static int dxt5ys_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) return 16; } +/** + * Compress one block of RGBA pixels in a RGTC1U texture and store the + * resulting bytes in 'dst'. Use the alpha channel of the input image. + * + * @param dst output buffer. + * @param stride scanline in bytes. + * @param block block to compress. + * @return how much texture data has been written. + */ +static int rgtc1u_alpha_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) +{ + compress_alpha(dst, stride, block); + + return 8; +} + av_cold void ff_texturedspenc_init(TextureDSPContext *c) { - c->dxt1_block = dxt1_block; - c->dxt5_block = dxt5_block; - c->dxt5ys_block = dxt5ys_block; + c->dxt1_block = dxt1_block; + c->dxt5_block = dxt5_block; + c->dxt5ys_block = dxt5ys_block; + c->rgtc1u_alpha_block = rgtc1u_alpha_block; } diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c new file mode 100644 index 000000000..93d04cb50 --- /dev/null +++ b/libavcodec/trace_headers_bsf.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/avstring.h" +#include "libavutil/common.h" +#include "libavutil/log.h" + +#include "bsf.h" +#include "cbs.h" + + +typedef struct TraceHeadersContext { + CodedBitstreamContext *cbc; +} TraceHeadersContext; + + +static int trace_headers_init(AVBSFContext *bsf) +{ + TraceHeadersContext *ctx = bsf->priv_data; + int err; + + err = ff_cbs_init(&ctx->cbc, bsf->par_in->codec_id, bsf); + if (err < 0) + return err; + + ctx->cbc->trace_enable = 1; + ctx->cbc->trace_level = AV_LOG_INFO; + + if (bsf->par_in->extradata) { + CodedBitstreamFragment ps; + + av_log(bsf, AV_LOG_INFO, "Extradata\n"); + + err = ff_cbs_read_extradata(ctx->cbc, &ps, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + return err; + } + + ff_cbs_fragment_uninit(ctx->cbc, &ps); + } + + return 0; +} + +static void trace_headers_close(AVBSFContext *bsf) +{ + TraceHeadersContext *ctx = bsf->priv_data; + + ff_cbs_close(&ctx->cbc); +} + +static int trace_headers(AVBSFContext *bsf, AVPacket *out) +{ + TraceHeadersContext *ctx = bsf->priv_data; + CodedBitstreamFragment au; + AVPacket *in; + char tmp[256] = { 0 }; + int err; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + if (in->flags & AV_PKT_FLAG_KEY) + av_strlcat(tmp, ", key frame", sizeof(tmp)); + if (in->flags & AV_PKT_FLAG_CORRUPT) + av_strlcat(tmp, ", corrupt", sizeof(tmp)); + + if (in->pts != AV_NOPTS_VALUE) + av_strlcatf(tmp, sizeof(tmp), ", pts %"PRId64, in->pts); + else + av_strlcat(tmp, ", no pts", sizeof(tmp)); + if (in->dts != AV_NOPTS_VALUE) + av_strlcatf(tmp, sizeof(tmp), ", dts %"PRId64, in->dts); + else + av_strlcat(tmp, ", no dts", sizeof(tmp)); + if (in->duration > 0) + av_strlcatf(tmp, sizeof(tmp), ", duration %"PRId64, in->duration); + + av_log(bsf, AV_LOG_INFO, "Packet: %d bytes%s.\n", in->size, tmp); + + err = ff_cbs_read_packet(ctx->cbc, &au, in); + if (err < 0) + return err; + + ff_cbs_fragment_uninit(ctx->cbc, &au); + + av_packet_move_ref(out, in); + av_packet_free(&in); + + return 0; +} + +static const enum AVCodecID trace_headers_codec_ids[] = { + AV_CODEC_ID_H264, + AV_CODEC_ID_HEVC, + AV_CODEC_ID_MPEG2VIDEO, + AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_trace_headers_bsf = { + .name = "trace_headers", + .priv_data_size = sizeof(TraceHeadersContext), + .init = &trace_headers_init, + .close = &trace_headers_close, + .filter = &trace_headers, + .codec_ids = trace_headers_codec_ids, +}; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 9551f312e..4c718432a 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -26,7 +26,6 @@ */ #include "config.h" -#include "libavutil/atomic.h" #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -45,6 +44,7 @@ #include "libavutil/thread.h" #include "avcodec.h" #include "decode.h" +#include "hwaccel.h" #include "libavutil/opt.h" #include "me_cmp.h" #include "mpegvideo.h" @@ -56,6 +56,7 @@ #include "version.h" #include #include +#include #include #include #if CONFIG_ICONV @@ -65,58 +66,7 @@ #include "libavutil/ffversion.h" const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; -#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS -static int default_lockmgr_cb(void **arg, enum AVLockOp op) -{ - void * volatile * mutex = arg; - int err; - - switch (op) { - case AV_LOCK_CREATE: - return 0; - case AV_LOCK_OBTAIN: - if (!*mutex) { - pthread_mutex_t *tmp = av_malloc(sizeof(pthread_mutex_t)); - if (!tmp) - return AVERROR(ENOMEM); - if ((err = pthread_mutex_init(tmp, NULL))) { - av_free(tmp); - return AVERROR(err); - } - if (avpriv_atomic_ptr_cas(mutex, NULL, tmp)) { - pthread_mutex_destroy(tmp); - av_free(tmp); - } - } - - if ((err = pthread_mutex_lock(*mutex))) - return AVERROR(err); - - return 0; - case AV_LOCK_RELEASE: - if ((err = pthread_mutex_unlock(*mutex))) - return AVERROR(err); - - return 0; - case AV_LOCK_DESTROY: - if (*mutex) - pthread_mutex_destroy(*mutex); - av_free(*mutex); - avpriv_atomic_ptr_cas(mutex, *mutex, NULL); - return 0; - } - return 1; -} -static int (*lockmgr_cb)(void **mutex, enum AVLockOp op) = default_lockmgr_cb; -#else -static int (*lockmgr_cb)(void **mutex, enum AVLockOp op) = NULL; -#endif - - -volatile int ff_avcodec_locked; -static int volatile entangled_thread_counter = 0; -static void *codec_mutex; -static void *avformat_mutex; +static AVMutex codec_mutex = AV_MUTEX_INITIALIZER; void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size) { @@ -176,38 +126,28 @@ int av_codec_is_decoder(const AVCodec *codec) return codec && (codec->decode || codec->receive_frame); } +static AVMutex codec_register_mutex = AV_MUTEX_INITIALIZER; + av_cold void avcodec_register(AVCodec *codec) { AVCodec **p; avcodec_init(); - p = last_avcodec; - codec->next = NULL; - while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec)) + ff_mutex_lock(&codec_register_mutex); + p = last_avcodec; + + while (*p) p = &(*p)->next; + *p = codec; + codec->next = NULL; last_avcodec = &codec->next; + ff_mutex_unlock(&codec_register_mutex); + if (codec->init_static_data) codec->init_static_data(codec); } -#if FF_API_EMU_EDGE -unsigned avcodec_get_edge_width(void) -{ - return EDGE_WIDTH; -} -#endif - -#if FF_API_SET_DIMENSIONS -void avcodec_set_dimensions(AVCodecContext *s, int width, int height) -{ - int ret = ff_set_dimensions(s, width, height); - if (ret < 0) { - av_log(s, AV_LOG_WARNING, "Failed to set dimensions %d %d\n", width, height); - } -} -#endif - 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); @@ -569,6 +509,7 @@ enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *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) @@ -584,6 +525,7 @@ 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); @@ -612,6 +554,19 @@ static int64_t get_bit_rate(AVCodecContext *ctx) 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; @@ -651,11 +606,9 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (options) av_dict_copy(&tmp, *options, 0); - ret = ff_lock_avcodec(avctx, codec); - if (ret < 0) - return ret; + ff_lock_avcodec(avctx, codec); - avctx->internal = av_mallocz(sizeof(AVCodecInternal)); + avctx->internal = av_mallocz(sizeof(*avctx->internal)); if (!avctx->internal) { ret = AVERROR(ENOMEM); goto end; @@ -833,12 +786,6 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code avctx->lowres = avctx->codec->max_lowres; } -#if FF_API_VISMV - if (avctx->debug_mv) - av_log(avctx, AV_LOG_WARNING, "The 'vismv' option is deprecated, " - "see the codecview filter instead.\n"); -#endif - if (av_codec_is_encoder(avctx->codec)) { int i; #if FF_API_CODED_FRAME @@ -1025,11 +972,6 @@ FF_ENABLE_DEPRECATION_WARNINGS ret=0; -#if FF_API_AUDIOENC_DELAY - if (av_codec_is_encoder(avctx->codec)) - avctx->delay = avctx->initial_padding; -#endif - if (av_codec_is_decoder(avctx->codec)) { if (!avctx->bit_rate) avctx->bit_rate = get_bit_rate(avctx); @@ -1157,7 +1099,7 @@ void avsubtitle_free(AVSubtitle *sub) av_freep(&sub->rects); - memset(sub, 0, sizeof(AVSubtitle)); + memset(sub, 0, sizeof(*sub)); } av_cold int avcodec_close(AVCodecContext *avctx) @@ -1836,13 +1778,13 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, /* calc from frame_bytes, channels, and bits_per_coded_sample */ switch (id) { case AV_CODEC_ID_PCM_DVD: - if(bps<4) + if(bps<4 || frame_bytes<3) return 0; - return 2 * (frame_bytes / ((bps * 2 / 8) * ch)); + return 2 * ((frame_bytes - 3) / ((bps * 2 / 8) * ch)); case AV_CODEC_ID_PCM_BLURAY: - if(bps<4) + if(bps<4 || frame_bytes<4) return 0; - return frame_bytes / ((FFALIGN(ch, 2) * bps) / 8); + return (frame_bytes - 4) / ((FFALIGN(ch, 2) * bps) / 8); case AV_CODEC_ID_S302M: return 2 * (frame_bytes / ((bps + 4) / 4)) / ch; } @@ -1911,143 +1853,34 @@ int ff_match_2uint16(const uint16_t(*tab)[2], int size, int a, int b) return i; } -#if FF_API_MISSING_SAMPLE -FF_DISABLE_DEPRECATION_WARNINGS -void av_log_missing_feature(void *avc, const char *feature, int want_sample) +const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index) { - av_log(avc, AV_LOG_WARNING, "%s 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", feature); - if(want_sample) - av_log_ask_for_sample(avc, NULL); + 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; } -void av_log_ask_for_sample(void *avc, const char *msg, ...) +#if FF_API_USER_VISIBLE_AVHWACCEL +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel) { - va_list argument_list; - - va_start(argument_list, msg); - - if (msg) - av_vlog(avc, AV_LOG_WARNING, msg, argument_list); - 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"); - - va_end(argument_list); + return NULL; } -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_MISSING_SAMPLE */ - -static AVHWAccel *first_hwaccel = NULL; -static AVHWAccel **last_hwaccel = &first_hwaccel; void av_register_hwaccel(AVHWAccel *hwaccel) { - AVHWAccel **p = last_hwaccel; - hwaccel->next = NULL; - while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel)) - p = &(*p)->next; - last_hwaccel = &hwaccel->next; -} - -AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel) -{ - return hwaccel ? hwaccel->next : first_hwaccel; } +#endif +#if FF_API_LOCKMGR int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)) { - if (lockmgr_cb) { - // There is no good way to rollback a failure to destroy the - // mutex, so we ignore failures. - lockmgr_cb(&codec_mutex, AV_LOCK_DESTROY); - lockmgr_cb(&avformat_mutex, AV_LOCK_DESTROY); - lockmgr_cb = NULL; - codec_mutex = NULL; - avformat_mutex = NULL; - } - - if (cb) { - void *new_codec_mutex = NULL; - void *new_avformat_mutex = NULL; - int err; - if (err = cb(&new_codec_mutex, AV_LOCK_CREATE)) { - return err > 0 ? AVERROR_UNKNOWN : err; - } - if (err = cb(&new_avformat_mutex, AV_LOCK_CREATE)) { - // Ignore failures to destroy the newly created mutex. - cb(&new_codec_mutex, AV_LOCK_DESTROY); - return err > 0 ? AVERROR_UNKNOWN : err; - } - lockmgr_cb = cb; - codec_mutex = new_codec_mutex; - avformat_mutex = new_avformat_mutex; - } - - return 0; -} - -int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec) -{ - if (codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE || !codec->init) - return 0; - - if (lockmgr_cb) { - if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN)) - return -1; - } - - if (avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, 1) != 1) { - av_log(log_ctx, AV_LOG_ERROR, - "Insufficient thread locking. At least %d threads are " - "calling avcodec_open2() at the same time right now.\n", - entangled_thread_counter); - if (!lockmgr_cb) - av_log(log_ctx, AV_LOG_ERROR, "No lock manager is set, please see av_lockmgr_register()\n"); - ff_avcodec_locked = 1; - ff_unlock_avcodec(codec); - return AVERROR(EINVAL); - } - av_assert0(!ff_avcodec_locked); - ff_avcodec_locked = 1; - return 0; -} - -int ff_unlock_avcodec(const AVCodec *codec) -{ - if (codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE || !codec->init) - return 0; - - av_assert0(ff_avcodec_locked); - ff_avcodec_locked = 0; - avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, -1); - if (lockmgr_cb) { - if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE)) - return -1; - } - - return 0; -} - -int avpriv_lock_avformat(void) -{ - if (lockmgr_cb) { - if ((*lockmgr_cb)(&avformat_mutex, AV_LOCK_OBTAIN)) - return -1; - } - return 0; -} - -int avpriv_unlock_avformat(void) -{ - if (lockmgr_cb) { - if ((*lockmgr_cb)(&avformat_mutex, AV_LOCK_RELEASE)) - return -1; - } return 0; } +#endif unsigned int avpriv_toupper4(unsigned int x) { diff --git a/libavcodec/utvideo.h b/libavcodec/utvideo.h index a8117851a..cf0bb28c4 100644 --- a/libavcodec/utvideo.h +++ b/libavcodec/utvideo.h @@ -72,17 +72,23 @@ typedef struct UtvideoContext { LLVidDSPContext llviddsp; LLVidEncDSPContext llvidencdsp; - uint32_t frame_info_size, flags, frame_info; + uint32_t frame_info_size, flags, frame_info, offset; int planes; int slices; int compression; int interlaced; int frame_pred; int pro; + int pack; ptrdiff_t slice_stride; uint8_t *slice_bits, *slice_buffer[4]; int slice_bits_size; + + const uint8_t *packed_stream[4][256]; + size_t packed_stream_size[4][256]; + const uint8_t *control_stream[4][256]; + size_t control_stream_size[4][256]; } UtvideoContext; typedef struct HuffEntry { diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 40c12772b..608c8c499 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -126,7 +126,7 @@ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym) } static int decode_plane10(UtvideoContext *c, int plane_no, - uint16_t *dst, int step, ptrdiff_t stride, + uint16_t *dst, ptrdiff_t stride, int width, int height, const uint8_t *src, const uint8_t *huff, int use_pred) @@ -152,7 +152,7 @@ static int decode_plane10(UtvideoContext *c, int plane_no, prev = 0x200; for (j = sstart; j < send; j++) { - for (i = 0; i < width * step; i += step) { + for (i = 0; i < width; i++) { pix = fsym; if (use_pred) { prev += pix; @@ -195,8 +195,7 @@ static int decode_plane10(UtvideoContext *c, int plane_no, prev = 0x200; for (j = sstart; j < send; j++) { - int ws = width * step; - for (i = 0; i < ws; i += step) { + for (i = 0; i < width; i++) { pix = get_vlc2(&gb, vlc.table, VLC_BITS, 3); if (pix < 0) { av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n"); @@ -229,8 +228,18 @@ fail: return AVERROR_INVALIDDATA; } +static int compute_cmask(int plane_no, int interlaced, enum AVPixelFormat pix_fmt) +{ + const int is_luma = (pix_fmt == AV_PIX_FMT_YUV420P) && !plane_no; + + if (interlaced) + return ~(1 + 2 * is_luma); + + return ~is_luma; +} + static int decode_plane(UtvideoContext *c, int plane_no, - uint8_t *dst, int step, ptrdiff_t stride, + uint8_t *dst, ptrdiff_t stride, int width, int height, const uint8_t *src, int use_pred) { @@ -238,8 +247,49 @@ static int decode_plane(UtvideoContext *c, int plane_no, int sstart, send; VLC vlc; GetBitContext gb; - int prev, fsym; - const int cmask = c->interlaced ? ~(1 + 2 * (!plane_no && c->avctx->pix_fmt == AV_PIX_FMT_YUV420P)) : ~(!plane_no && c->avctx->pix_fmt == AV_PIX_FMT_YUV420P); + int ret, prev, fsym; + const int cmask = compute_cmask(plane_no, c->interlaced, c->avctx->pix_fmt); + + if (c->pack) { + send = 0; + for (slice = 0; slice < c->slices; slice++) { + GetBitContext cbit, pbit; + uint8_t *dest, *p; + + ret = init_get_bits8(&cbit, c->control_stream[plane_no][slice], c->control_stream_size[plane_no][slice]); + if (ret < 0) + return ret; + + ret = init_get_bits8(&pbit, c->packed_stream[plane_no][slice], c->packed_stream_size[plane_no][slice]); + if (ret < 0) + return ret; + + sstart = send; + send = (height * (slice + 1) / c->slices) & cmask; + dest = dst + sstart * stride; + + for (p = dest; p < dst + send * stride; p += 8) { + int bits = get_bits_le(&cbit, 3); + + if (bits == 0) { + *(uint64_t *) p = 0; + } else { + uint32_t sub = 0x80 >> (8 - (bits + 1)), add; + int k; + + for (k = 0; k < 8; k++) { + + p[k] = get_bits_le(&pbit, bits + 1); + add = (~p[k] & sub) << (8 - bits); + p[k] -= sub; + p[k] += add; + } + } + } + } + + return 0; + } if (build_huff(src, &vlc, &fsym)) { av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n"); @@ -256,7 +306,7 @@ static int decode_plane(UtvideoContext *c, int plane_no, prev = 0x80; for (j = sstart; j < send; j++) { - for (i = 0; i < width * step; i += step) { + for (i = 0; i < width; i++) { pix = fsym; if (use_pred) { prev += pix; @@ -300,8 +350,7 @@ static int decode_plane(UtvideoContext *c, int plane_no, prev = 0x80; for (j = sstart; j < send; j++) { - int ws = width * step; - for (i = 0; i < ws; i += step) { + for (i = 0; i < width; i++) { pix = get_vlc2(&gb, vlc.table, VLC_BITS, 3); if (pix < 0) { av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n"); @@ -365,12 +414,16 @@ static void restore_median_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t str C = bsrc[-stride]; bsrc[0] += C; A = bsrc[0]; - for (i = 1; i < width; i++) { + for (i = 1; i < FFMIN(width, 16); i++) { /* scalar loop (DSP need align 16) */ B = bsrc[i - stride]; bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); C = B; A = bsrc[i]; } + if (width > 16) + c->llviddsp.add_median_pred(bsrc + 16, bsrc - stride + 16, + bsrc + 16, width - 16, &A, &B); + bsrc += stride; // the rest of lines use continuous median prediction for (j = 2; j < slice_height; j++) { @@ -416,12 +469,16 @@ static void restore_median_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_t C = bsrc[-stride2]; bsrc[0] += C; A = bsrc[0]; - for (i = 1; i < width; i++) { + for (i = 1; i < FFMIN(width, 16); i++) { /* scalar loop (DSP need align 16) */ B = bsrc[i - stride2]; bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); C = B; A = bsrc[i]; } + if (width > 16) + c->llviddsp.add_median_pred(bsrc + 16, bsrc - stride2 + 16, + bsrc + 16, width - 16, &A, &B); + c->llviddsp.add_median_pred(bsrc + stride, bsrc - stride, bsrc + stride, width, &A, &B); bsrc += stride2; @@ -444,6 +501,7 @@ static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t s uint8_t *bsrc; int slice_start, slice_height; const int cmask = ~rmode; + int min_width = FFMIN(width, 32); for (slice = 0; slice < slices; slice++) { slice_start = ((slice * height) / slices) & cmask; @@ -463,12 +521,14 @@ static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t s for (j = 1; j < slice_height; j++) { // second line - first element has top prediction, the rest uses gradient bsrc[0] = (bsrc[0] + bsrc[-stride]) & 0xFF; - for (i = 1; i < width; i++) { + for (i = 1; i < min_width; i++) { /* dsp need align 32 */ A = bsrc[i - stride]; B = bsrc[i - (stride + 1)]; C = bsrc[i - 1]; bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; } + if (width > 32) + c->llviddsp.add_gradient_pred(bsrc + 32, stride, width - 32); bsrc += stride; } } @@ -483,6 +543,7 @@ static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_ int slice_start, slice_height; const int cmask = ~(rmode ? 3 : 1); const ptrdiff_t stride2 = stride << 1; + int min_width = FFMIN(width, 32); for (slice = 0; slice < slices; slice++) { slice_start = ((slice * height) / slices) & cmask; @@ -504,12 +565,15 @@ static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_ for (j = 1; j < slice_height; j++) { // second line - first element has top prediction, the rest uses gradient bsrc[0] = (bsrc[0] + bsrc[-stride2]) & 0xFF; - for (i = 1; i < width; i++) { + for (i = 1; i < min_width; i++) { /* dsp need align 32 */ A = bsrc[i - stride2]; B = bsrc[i - (stride2 + 1)]; C = bsrc[i - 1]; bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; } + if (width > 32) + c->llviddsp.add_gradient_pred(bsrc + 32, stride2, width - 32); + A = bsrc[-stride]; B = bsrc[-(1 + stride + stride - width)]; C = bsrc[width - 1]; @@ -543,7 +607,58 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, /* parse plane structure to get frame flags and validate slice offsets */ bytestream2_init(&gb, buf, buf_size); - if (c->pro) { + + if (c->pack) { + const uint8_t *packed_stream; + const uint8_t *control_stream; + GetByteContext pb; + uint32_t nb_cbs; + int left; + + c->frame_info = PRED_GRADIENT << 8; + + if (bytestream2_get_byte(&gb) != 1) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gb, 3); + c->offset = bytestream2_get_le32(&gb); + + if (buf_size <= c->offset + 8LL) + return AVERROR_INVALIDDATA; + + bytestream2_init(&pb, buf + 8 + c->offset, buf_size - 8 - c->offset); + + nb_cbs = bytestream2_get_le32(&pb); + if (nb_cbs > c->offset) + return AVERROR_INVALIDDATA; + + packed_stream = buf + 8; + control_stream = packed_stream + (c->offset - nb_cbs); + left = control_stream - packed_stream; + + for (i = 0; i < c->planes; i++) { + for (j = 0; j < c->slices; j++) { + c->packed_stream[i][j] = packed_stream; + c->packed_stream_size[i][j] = bytestream2_get_le32(&pb); + left -= c->packed_stream_size[i][j]; + if (left < 0) + return AVERROR_INVALIDDATA; + packed_stream += c->packed_stream_size[i][j]; + } + } + + left = buf + buf_size - control_stream; + + for (i = 0; i < c->planes; i++) { + for (j = 0; j < c->slices; j++) { + c->control_stream[i][j] = control_stream; + c->control_stream_size[i][j] = bytestream2_get_le32(&pb); + left -= c->control_stream_size[i][j]; + if (left < 0) + return AVERROR_INVALIDDATA; + control_stream += c->control_stream_size[i][j]; + } + } + } else if (c->pro) { if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) { av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n"); return AVERROR_INVALIDDATA; @@ -612,19 +727,21 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, max_slice_size += 4*avctx->width; - av_fast_malloc(&c->slice_bits, &c->slice_bits_size, - max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!c->pack) { + av_fast_malloc(&c->slice_bits, &c->slice_bits_size, + max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!c->slice_bits) { - av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n"); - return AVERROR(ENOMEM); + if (!c->slice_bits) { + av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n"); + return AVERROR(ENOMEM); + } } switch (c->avctx->pix_fmt) { case AV_PIX_FMT_GBRP: case AV_PIX_FMT_GBRAP: for (i = 0; i < c->planes; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width, avctx->height, plane_start[i], c->frame_pred == PRED_LEFT); @@ -661,7 +778,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, case AV_PIX_FMT_GBRAP10: case AV_PIX_FMT_GBRP10: for (i = 0; i < c->planes; i++) { - ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, + ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], frame.f->linesize[i] / 2, avctx->width, avctx->height, plane_start[i], plane_start[i + 1] - 1024, @@ -675,7 +792,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV420P: for (i = 0; i < 3; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width >> !!i, avctx->height >> !!i, plane_start[i], c->frame_pred == PRED_LEFT); if (ret) @@ -707,7 +824,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV422P: for (i = 0; i < 3; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width >> !!i, avctx->height, plane_start[i], c->frame_pred == PRED_LEFT); if (ret) @@ -737,7 +854,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV444P: for (i = 0; i < 3; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width, avctx->height, plane_start[i], c->frame_pred == PRED_LEFT); if (ret) @@ -767,7 +884,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV422P10: for (i = 0; i < 3; i++) { - ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, frame.f->linesize[i] / 2, + ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], frame.f->linesize[i] / 2, avctx->width >> !!i, avctx->height, plane_start[i], plane_start[i + 1] - 1024, c->frame_pred == PRED_LEFT); if (ret) @@ -796,37 +913,6 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&c->bdsp); ff_llviddsp_init(&c->llviddsp); - if (avctx->extradata_size >= 16) { - av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", - avctx->extradata[3], avctx->extradata[2], - avctx->extradata[1], avctx->extradata[0]); - av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", - AV_RB32(avctx->extradata + 4)); - c->frame_info_size = AV_RL32(avctx->extradata + 8); - c->flags = AV_RL32(avctx->extradata + 12); - - if (c->frame_info_size != 4) - avpriv_request_sample(avctx, "Frame info not 4 bytes"); - av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags); - c->slices = (c->flags >> 24) + 1; - c->compression = c->flags & 1; - c->interlaced = c->flags & 0x800; - } else if (avctx->extradata_size == 8) { - av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", - avctx->extradata[3], avctx->extradata[2], - avctx->extradata[1], avctx->extradata[0]); - av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", - AV_RB32(avctx->extradata + 4)); - c->interlaced = 0; - c->pro = 1; - c->frame_info_size = 4; - } else { - av_log(avctx, AV_LOG_ERROR, - "Insufficient extradata size %d, should be at least 16\n", - avctx->extradata_size); - return AVERROR_INVALIDDATA; - } - c->slice_bits_size = 0; switch (avctx->codec_tag) { @@ -880,12 +966,87 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_YUV444P; avctx->colorspace = AVCOL_SPC_BT709; break; + case MKTAG('U', 'M', 'Y', '2'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV422P; + avctx->colorspace = AVCOL_SPC_BT470BG; + break; + case MKTAG('U', 'M', 'H', '2'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV422P; + avctx->colorspace = AVCOL_SPC_BT709; + break; + case MKTAG('U', 'M', 'Y', '4'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->colorspace = AVCOL_SPC_BT470BG; + break; + case MKTAG('U', 'M', 'H', '4'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->colorspace = AVCOL_SPC_BT709; + break; + case MKTAG('U', 'M', 'R', 'G'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_GBRP; + break; + case MKTAG('U', 'M', 'R', 'A'): + c->planes = 4; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; + break; default: av_log(avctx, AV_LOG_ERROR, "Unknown Ut Video FOURCC provided (%08X)\n", avctx->codec_tag); return AVERROR_INVALIDDATA; } + if (c->pack && avctx->extradata_size >= 16) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->compression = avctx->extradata[8]; + if (c->compression != 2) + avpriv_request_sample(avctx, "Unknown compression type"); + c->slices = avctx->extradata[9] + 1; + } else if (avctx->extradata_size >= 16) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->frame_info_size = AV_RL32(avctx->extradata + 8); + c->flags = AV_RL32(avctx->extradata + 12); + + if (c->frame_info_size != 4) + avpriv_request_sample(avctx, "Frame info not 4 bytes"); + av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags); + c->slices = (c->flags >> 24) + 1; + c->compression = c->flags & 1; + c->interlaced = c->flags & 0x800; + } else if (avctx->extradata_size == 8) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->interlaced = 0; + c->pro = 1; + c->frame_info_size = 4; + } else { + av_log(avctx, AV_LOG_ERROR, + "Insufficient extradata size %d, should be at least 16\n", + avctx->extradata_size); + return AVERROR_INVALIDDATA; + } + return 0; } diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c index 840742caf..a829b7aaa 100644 --- a/libavcodec/utvideoenc.c +++ b/libavcodec/utvideoenc.c @@ -67,12 +67,12 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) c->slice_stride = FFALIGN(avctx->width, 32); switch (avctx->pix_fmt) { - case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_GBRP: c->planes = 3; avctx->codec_tag = MKTAG('U', 'L', 'R', 'G'); original_format = UTVIDEO_RGB; break; - case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_GBRAP: c->planes = 4; avctx->codec_tag = MKTAG('U', 'L', 'R', 'A'); original_format = UTVIDEO_RGBA; @@ -243,36 +243,43 @@ FF_ENABLE_DEPRECATION_WARNINGS } static void mangle_rgb_planes(uint8_t *dst[4], ptrdiff_t dst_stride, - uint8_t *src, int step, ptrdiff_t stride, + uint8_t *const src[4], int planes, const int stride[4], int width, int height) { int i, j; int k = 2 * dst_stride; + const uint8_t *sg = src[0]; + const uint8_t *sb = src[1]; + const uint8_t *sr = src[2]; + const uint8_t *sa = src[3]; unsigned int g; for (j = 0; j < height; j++) { - if (step == 3) { - for (i = 0; i < width * step; i += step) { - g = src[i + 1]; + if (planes == 3) { + for (i = 0; i < width; i++) { + g = sg[i]; dst[0][k] = g; g += 0x80; - dst[1][k] = src[i + 2] - g; - dst[2][k] = src[i + 0] - g; + dst[1][k] = sb[i] - g; + dst[2][k] = sr[i] - g; k++; } } else { - for (i = 0; i < width * step; i += step) { - g = src[i + 1]; + for (i = 0; i < width; i++) { + g = sg[i]; dst[0][k] = g; g += 0x80; - dst[1][k] = src[i + 2] - g; - dst[2][k] = src[i + 0] - g; - dst[3][k] = src[i + 3]; + dst[1][k] = sb[i] - g; + dst[2][k] = sr[i] - g; + dst[3][k] = sa[i]; k++; } + sa += stride[3]; } k += dst_stride - width; - src += stride; + sg += stride[0]; + sb += stride[1]; + sr += stride[2]; } } @@ -572,14 +579,14 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } /* In case of RGB, mangle the planes to Ut Video's format */ - if (avctx->pix_fmt == AV_PIX_FMT_RGBA || avctx->pix_fmt == AV_PIX_FMT_RGB24) - mangle_rgb_planes(c->slice_buffer, c->slice_stride, pic->data[0], - c->planes, pic->linesize[0], width, height); + if (avctx->pix_fmt == AV_PIX_FMT_GBRAP || avctx->pix_fmt == AV_PIX_FMT_GBRP) + mangle_rgb_planes(c->slice_buffer, c->slice_stride, pic->data, + c->planes, pic->linesize, width, height); /* Deal with the planes */ switch (avctx->pix_fmt) { - case AV_PIX_FMT_RGB24: - case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: for (i = 0; i < c->planes; i++) { ret = encode_plane(avctx, c->slice_buffer[i] + 2 * c->slice_stride, c->slice_buffer[i], c->slice_stride, i, @@ -690,7 +697,7 @@ AVCodec ff_utvideo_encoder = { .close = utvideo_encode_close, .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, .pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, }; diff --git a/libavcodec/v210dec.c b/libavcodec/v210dec.c index 9af9af679..99199ddc1 100644 --- a/libavcodec/v210dec.c +++ b/libavcodec/v210dec.c @@ -162,10 +162,10 @@ static const AVOption v210dec_options[] = { }; static const AVClass v210dec_class = { - "V210 Decoder", - av_default_item_name, - v210dec_options, - LIBAVUTIL_VERSION_INT, + .class_name = "V210 Decoder", + .item_name = av_default_item_name, + .option = v210dec_options, + .version = LIBAVUTIL_VERSION_INT, }; AVCodec ff_v210_decoder = { diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index 9f3b56dda..4c169928f 100644 --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -484,7 +484,7 @@ static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p) * *****************************************************************************/ -int ff_v4l2_context_set_status(V4L2Context* ctx, int cmd) +int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd) { int type = ctx->type; int ret; diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h index 503cc36dc..632f1d0aa 100644 --- a/libavcodec/v4l2_context.h +++ b/libavcodec/v4l2_context.h @@ -135,7 +135,7 @@ void ff_v4l2_context_release(V4L2Context* ctx); * those frames will be dropped. * @return 0 in case of success, a negative value representing the error otherwise. */ -int ff_v4l2_context_set_status(V4L2Context* ctx, int cmd); +int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd); /** * Dequeues a buffer from a V4L2Context to an AVPacket. diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c index 958cdc522..830861397 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -215,6 +215,8 @@ AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \ .receive_frame = v4l2_receive_frame,\ .close = ff_v4l2_m2m_codec_end,\ .bsfs = bsf_name, \ + .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .wrapper_name = "v4l2m2m", \ }; M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb"); diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c index f71ce5fb7..7e88f4d2e 100644 --- a/libavcodec/v4l2_m2m_enc.c +++ b/libavcodec/v4l2_m2m_enc.c @@ -204,7 +204,7 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s) v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile"); qmin_cid = MPEG_CID(MPEG4_MIN_QP); qmax_cid = MPEG_CID(MPEG4_MAX_QP); - if (avctx->flags & CODEC_FLAG_QPEL) + if (avctx->flags & AV_CODEC_FLAG_QPEL) v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_QPEL), 1, "qpel"); qmin = 1; qmax = 31; @@ -335,6 +335,8 @@ AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \ .send_frame = v4l2_send_frame,\ .receive_packet = v4l2_receive_packet,\ .close = ff_v4l2_m2m_codec_end,\ + .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .wrapper_name = "v4l2m2m", \ }; M2MENC(mpeg4,"MPEG4", AV_CODEC_ID_MPEG4); diff --git a/libavcodec/vaapi.h b/libavcodec/vaapi.h index bb2845532..2cf7da588 100644 --- a/libavcodec/vaapi.h +++ b/libavcodec/vaapi.h @@ -77,115 +77,6 @@ struct attribute_deprecated vaapi_context { * - decoding: Set by user */ uint32_t context_id; - -#if FF_API_VAAPI_CONTEXT - /** - * VAPictureParameterBuffer ID - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t pic_param_buf_id; - - /** - * VAIQMatrixBuffer ID - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t iq_matrix_buf_id; - - /** - * VABitPlaneBuffer ID (for VC-1 decoding) - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t bitplane_buf_id; - - /** - * Slice parameter/data buffer IDs - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t *slice_buf_ids; - - /** - * Number of effective slice buffer IDs to send to the HW - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int n_slice_buf_ids; - - /** - * Size of pre-allocated slice_buf_ids - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_buf_ids_alloc; - - /** - * Pointer to VASliceParameterBuffers - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - void *slice_params; - - /** - * Size of a VASliceParameterBuffer element - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_param_size; - - /** - * Size of pre-allocated slice_params - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_params_alloc; - - /** - * Number of slices currently filled in - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_count; - - /** - * Pointer to slice data buffer base - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - const uint8_t *slice_data; - - /** - * Current size of slice data - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t slice_data_size; -#endif }; /* @} */ diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index 27ef33837..572b3a40a 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -21,6 +21,7 @@ #include "libavutil/pixdesc.h" #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "vaapi_decode.h" @@ -272,26 +273,34 @@ static const struct { #undef MAP }; -static int vaapi_decode_make_config(AVCodecContext *avctx) +/* + * Set *va_config and the frames_ref fields from the current codec parameters + * in avctx. + */ +static int vaapi_decode_make_config(AVCodecContext *avctx, + AVBufferRef *device_ref, + VAConfigID *va_config, + AVBufferRef *frames_ref) { - VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; - AVVAAPIHWConfig *hwconfig = NULL; AVHWFramesConstraints *constraints = NULL; VAStatus vas; int err, i, j; const AVCodecDescriptor *codec_desc; - VAProfile profile, va_profile, *profile_list = NULL; - int profile_count, exact_match, alt_profile; + VAProfile *profile_list = NULL, matched_va_profile; + int profile_count, exact_match, matched_ff_profile; const AVPixFmtDescriptor *sw_desc, *desc; + AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data; + AVVAAPIDeviceContext *hwctx = device->hwctx; + codec_desc = avcodec_descriptor_get(avctx->codec_id); if (!codec_desc) { err = AVERROR(EINVAL); goto fail; } - profile_count = vaMaxNumProfiles(ctx->hwctx->display); + profile_count = vaMaxNumProfiles(hwctx->display); profile_list = av_malloc_array(profile_count, sizeof(VAProfile)); if (!profile_list) { @@ -299,7 +308,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - vas = vaQueryConfigProfiles(ctx->hwctx->display, + vas = vaQueryConfigProfiles(hwctx->display, profile_list, &profile_count); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: " @@ -308,32 +317,32 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - profile = VAProfileNone; + matched_va_profile = VAProfileNone; exact_match = 0; for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) { int profile_match = 0; if (avctx->codec_id != vaapi_profile_map[i].codec_id) continue; - if (avctx->profile == vaapi_profile_map[i].codec_profile) + if (avctx->profile == vaapi_profile_map[i].codec_profile || + vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN) profile_match = 1; - profile = vaapi_profile_map[i].va_profile; for (j = 0; j < profile_count; j++) { - if (profile == profile_list[j]) { + if (vaapi_profile_map[i].va_profile == profile_list[j]) { exact_match = profile_match; break; } } if (j < profile_count) { + matched_va_profile = vaapi_profile_map[i].va_profile; + matched_ff_profile = vaapi_profile_map[i].codec_profile; if (exact_match) break; - alt_profile = vaapi_profile_map[i].codec_profile; - va_profile = vaapi_profile_map[i].va_profile; } } av_freep(&profile_list); - if (profile == VAProfileNone) { + if (matched_va_profile == VAProfileNone) { av_log(avctx, AV_LOG_ERROR, "No support for codec %s " "profile %d.\n", codec_desc->name, avctx->profile); err = AVERROR(ENOSYS); @@ -347,8 +356,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) codec_desc->name, avctx->profile); av_log(avctx, AV_LOG_WARNING, "Using possibly-" "incompatible profile %d instead.\n", - alt_profile); - profile = va_profile; + matched_ff_profile); } else { av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " "supported for hardware decode.\n", @@ -358,12 +366,9 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) } } - ctx->va_profile = profile; - ctx->va_entrypoint = VAEntrypointVLD; - - vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile, - ctx->va_entrypoint, NULL, 0, - &ctx->va_config); + vas = vaCreateConfig(hwctx->display, matched_va_profile, + VAEntrypointVLD, NULL, 0, + va_config); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create decode " "configuration: %d (%s).\n", vas, vaErrorStr(vas)); @@ -371,20 +376,15 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - hwconfig = av_hwdevice_hwconfig_alloc(avctx->hw_device_ctx ? - avctx->hw_device_ctx : - ctx->frames->device_ref); + hwconfig = av_hwdevice_hwconfig_alloc(device_ref); if (!hwconfig) { err = AVERROR(ENOMEM); goto fail; } - hwconfig->config_id = ctx->va_config; + hwconfig->config_id = *va_config; constraints = - av_hwdevice_get_hwframe_constraints(avctx->hw_device_ctx ? - avctx->hw_device_ctx : - ctx->frames->device_ref, - hwconfig); + av_hwdevice_get_hwframe_constraints(device_ref, hwconfig); if (!constraints) { err = AVERROR(ENOMEM); goto fail; @@ -410,48 +410,52 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - // Find the first format in the list which matches the expected - // bit depth and subsampling. If none are found (this can happen - // when 10-bit streams are decoded to 8-bit surfaces, for example) - // then just take the first format on the list. - ctx->surface_format = constraints->valid_sw_formats[0]; - sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); - for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { - desc = av_pix_fmt_desc_get(constraints->valid_sw_formats[i]); - if (desc->nb_components != sw_desc->nb_components || - desc->log2_chroma_w != sw_desc->log2_chroma_w || - desc->log2_chroma_h != sw_desc->log2_chroma_h) - continue; - for (j = 0; j < desc->nb_components; j++) { - if (desc->comp[j].depth != sw_desc->comp[j].depth) - break; - } - if (j < desc->nb_components) - continue; - ctx->surface_format = constraints->valid_sw_formats[i]; - break; - } + if (frames_ref) { + AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data; - // Start with at least four surfaces. - ctx->surface_count = 4; - // Add per-codec number of surfaces used for storing reference frames. - switch (avctx->codec_id) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_HEVC: - ctx->surface_count += 16; - break; - case AV_CODEC_ID_VP9: - ctx->surface_count += 8; - break; - case AV_CODEC_ID_VP8: - ctx->surface_count += 3; - break; - default: - ctx->surface_count += 2; + frames->format = AV_PIX_FMT_VAAPI; + frames->width = avctx->coded_width; + frames->height = avctx->coded_height; + + // Find the first format in the list which matches the expected + // bit depth and subsampling. If none are found (this can happen + // when 10-bit streams are decoded to 8-bit surfaces, for example) + // then just take the first format on the list. + frames->sw_format = constraints->valid_sw_formats[0]; + sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { + desc = av_pix_fmt_desc_get(constraints->valid_sw_formats[i]); + if (desc->nb_components != sw_desc->nb_components || + desc->log2_chroma_w != sw_desc->log2_chroma_w || + desc->log2_chroma_h != sw_desc->log2_chroma_h) + continue; + for (j = 0; j < desc->nb_components; j++) { + if (desc->comp[j].depth != sw_desc->comp[j].depth) + break; + } + if (j < desc->nb_components) + continue; + frames->sw_format = constraints->valid_sw_formats[i]; + break; + } + + frames->initial_pool_size = 1; + // Add per-codec number of surfaces used for storing reference frames. + switch (avctx->codec_id) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_HEVC: + frames->initial_pool_size += 16; + break; + case AV_CODEC_ID_VP9: + frames->initial_pool_size += 8; + break; + case AV_CODEC_ID_VP8: + frames->initial_pool_size += 3; + break; + default: + frames->initial_pool_size += 2; + } } - // Add an additional surface per thread is frame threading is enabled. - if (avctx->active_thread_type & FF_THREAD_FRAME) - ctx->surface_count += avctx->thread_count; av_hwframe_constraints_free(&constraints); av_freep(&hwconfig); @@ -461,14 +465,38 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) fail: av_hwframe_constraints_free(&constraints); av_freep(&hwconfig); - if (ctx->va_config != VA_INVALID_ID) { - vaDestroyConfig(ctx->hwctx->display, ctx->va_config); - ctx->va_config = VA_INVALID_ID; + if (*va_config != VA_INVALID_ID) { + vaDestroyConfig(hwctx->display, *va_config); + *va_config = VA_INVALID_ID; } av_freep(&profile_list); return err; } +int ff_vaapi_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data; + AVHWDeviceContext *device_ctx = hw_frames->device_ctx; + AVVAAPIDeviceContext *hwctx; + VAConfigID va_config = VA_INVALID_ID; + int err; + + if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI) + return AVERROR(EINVAL); + hwctx = device_ctx->hwctx; + + err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config, + hw_frames_ctx); + if (err) + return err; + + if (va_config != VA_INVALID_ID) + vaDestroyConfig(hwctx->display, va_config); + + return 0; +} + int ff_vaapi_decode_init(AVCodecContext *avctx) { VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; @@ -505,36 +533,8 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) ctx->hwctx->driver_quirks = AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS; - } else -#endif - if (avctx->hw_frames_ctx) { - // This structure has a shorter lifetime than the enclosing - // AVCodecContext, so we inherit the references from there - // and do not need to make separate ones. - - ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - ctx->hwfc = ctx->frames->hwctx; - ctx->device = ctx->frames->device_ctx; - ctx->hwctx = ctx->device->hwctx; - - } else if (avctx->hw_device_ctx) { - ctx->device = (AVHWDeviceContext*)avctx->hw_device_ctx->data; - ctx->hwctx = ctx->device->hwctx; - - if (ctx->device->type != AV_HWDEVICE_TYPE_VAAPI) { - av_log(avctx, AV_LOG_ERROR, "Device supplied for VAAPI " - "decoding must be a VAAPI device (not %d).\n", - ctx->device->type); - err = AVERROR(EINVAL); - goto fail; - } - - } else { - av_log(avctx, AV_LOG_ERROR, "A hardware device or frames context " - "is required for VAAPI decoding.\n"); - err = AVERROR(EINVAL); - goto fail; } +#endif #if FF_API_STRUCT_VAAPI_CONTEXT if (ctx->have_old_context) { @@ -546,34 +546,19 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) } else { #endif - err = vaapi_decode_make_config(avctx); - if (err) + err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI); + if (err < 0) goto fail; - if (!avctx->hw_frames_ctx) { - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); - if (!avctx->hw_frames_ctx) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx->hwfc = ctx->frames->hwctx; + ctx->device = ctx->frames->device_ctx; + ctx->hwctx = ctx->device->hwctx; - ctx->frames->format = AV_PIX_FMT_VAAPI; - ctx->frames->width = avctx->coded_width; - ctx->frames->height = avctx->coded_height; - - ctx->frames->sw_format = ctx->surface_format; - ctx->frames->initial_pool_size = ctx->surface_count; - - err = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal " - "frames context: %d.\n", err); - goto fail; - } - - ctx->hwfc = ctx->frames->hwctx; - } + err = vaapi_decode_make_config(avctx, ctx->frames->device_ref, + &ctx->va_config, avctx->hw_frames_ctx); + if (err) + goto fail; vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, avctx->coded_width, avctx->coded_height, diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h index 550ee0543..1fcecac46 100644 --- a/libavcodec/vaapi_decode.h +++ b/libavcodec/vaapi_decode.h @@ -53,8 +53,6 @@ typedef struct VAAPIDecodePicture { } VAAPIDecodePicture; typedef struct VAAPIDecodeContext { - VAProfile va_profile; - VAEntrypoint va_entrypoint; VAConfigID va_config; VAContextID va_context; @@ -98,4 +96,7 @@ int ff_vaapi_decode_cancel(AVCodecContext *avctx, int ff_vaapi_decode_init(AVCodecContext *avctx); int ff_vaapi_decode_uninit(AVCodecContext *avctx); +int ff_vaapi_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx); + #endif /* AVCODEC_VAAPI_DECODE_H */ diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 590f4be4e..550ea4799 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -1036,6 +1036,8 @@ static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) // Unfortunately we have to treat this as "don't know" and hope // for the best, because the Intel MJPEG encoder returns this // for all the interesting attributes. + av_log(avctx, AV_LOG_DEBUG, "Attribute (%d) is not supported.\n", + attr[i].type); continue; } switch (attr[i].type) { diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index efde80b08..a7f9a6025 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -16,128 +16,37 @@ * 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/internal.h" #include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" +#include "cbs.h" +#include "cbs_h264.h" #include "h264.h" #include "h264_sei.h" #include "internal.h" #include "vaapi_encode.h" -#include "vaapi_encode_h26x.h" enum { - SLICE_TYPE_P = 0, - SLICE_TYPE_B = 1, - SLICE_TYPE_I = 2, - SLICE_TYPE_SP = 3, - SLICE_TYPE_SI = 4, + SEI_TIMING = 0x01, + SEI_IDENTIFIER = 0x02, + SEI_RECOVERY_POINT = 0x04, }; -// This structure contains all possibly-useful per-sequence syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH264MiscSequenceParams { - unsigned int profile_idc; - char constraint_set0_flag; - char constraint_set1_flag; - char constraint_set2_flag; - char constraint_set3_flag; - char constraint_set4_flag; - char constraint_set5_flag; - - char separate_colour_plane_flag; - char qpprime_y_zero_transform_bypass_flag; - - char gaps_in_frame_num_allowed_flag; - char delta_pic_order_always_zero_flag; - char bottom_field_pic_order_in_frame_present_flag; - - unsigned int num_slice_groups_minus1; - unsigned int slice_group_map_type; - - int pic_init_qs_minus26; - - char overscan_info_present_flag; - char overscan_appropriate_flag; - - char video_signal_type_present_flag; - unsigned int video_format; - char video_full_range_flag; - char colour_description_present_flag; - unsigned int colour_primaries; - unsigned int transfer_characteristics; - unsigned int matrix_coefficients; - - char chroma_loc_info_present_flag; - unsigned int chroma_sample_loc_type_top_field; - unsigned int chroma_sample_loc_type_bottom_field; - - // Some timing elements are in VAEncSequenceParameterBufferH264. - char fixed_frame_rate_flag; - - char nal_hrd_parameters_present_flag; - char vcl_hrd_parameters_present_flag; - char low_delay_hrd_flag; - char pic_struct_present_flag; - - char motion_vectors_over_pic_boundaries_flag; - unsigned int max_bytes_per_pic_denom; - unsigned int max_bits_per_mb_denom; - unsigned int max_num_reorder_frames; - unsigned int max_dec_pic_buffering; - - unsigned int cpb_cnt_minus1; - unsigned int bit_rate_scale; - unsigned int cpb_size_scale; - unsigned int bit_rate_value_minus1[32]; - unsigned int cpb_size_value_minus1[32]; - char cbr_flag[32]; - unsigned int initial_cpb_removal_delay_length_minus1; - unsigned int cpb_removal_delay_length_minus1; - unsigned int dpb_output_delay_length_minus1; - unsigned int time_offset_length; - - unsigned int initial_cpb_removal_delay; - unsigned int initial_cpb_removal_delay_offset; - - unsigned int pic_struct; -} VAAPIEncodeH264MiscSequenceParams; - -// This structure contains all possibly-useful per-slice syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH264MiscSliceParams { - unsigned int nal_unit_type; - unsigned int nal_ref_idc; - - unsigned int colour_plane_id; - char field_pic_flag; - char bottom_field_flag; - - unsigned int redundant_pic_cnt; - - char sp_for_switch_flag; - int slice_qs_delta; - - char ref_pic_list_modification_flag_l0; - char ref_pic_list_modification_flag_l1; - - char no_output_of_prior_pics_flag; - char long_term_reference_flag; - char adaptive_ref_pic_marking_mode_flag; -} VAAPIEncodeH264MiscSliceParams; - -typedef struct VAAPIEncodeH264Slice { - VAAPIEncodeH264MiscSliceParams misc_slice_params; -} VAAPIEncodeH264Slice; +// Random (version 4) ISO 11578 UUID. +static const uint8_t vaapi_encode_h264_sei_identifier_uuid[16] = { + 0x59, 0x94, 0x8b, 0x28, 0x11, 0xec, 0x45, 0xaf, + 0x96, 0x75, 0x19, 0xd4, 0x1f, 0xea, 0xa9, 0x4d, +}; typedef struct VAAPIEncodeH264Context { - VAAPIEncodeH264MiscSequenceParams misc_sequence_params; - int mb_width; int mb_height; @@ -145,15 +54,35 @@ typedef struct VAAPIEncodeH264Context { int fixed_qp_p; int fixed_qp_b; + H264RawAUD aud; + H264RawSPS sps; + H264RawPPS pps; + H264RawSEI sei; + H264RawSlice slice; + + H264RawSEIBufferingPeriod buffering_period; + H264RawSEIPicTiming pic_timing; + H264RawSEIRecoveryPoint recovery_point; + H264RawSEIUserDataUnregistered identifier; + char *identifier_string; + + int frame_num; + int pic_order_cnt; int next_frame_num; int64_t last_idr_frame; int64_t idr_pic_count; + int primary_pic_type; + int slice_type; + int cpb_delay; int dpb_delay; - // Rate control configuration. - int send_timing_sei; + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_access_unit; + int aud_needed; + int sei_needed; + int sei_cbr_workaround_needed; } VAAPIEncodeH264Context; typedef struct VAAPIEncodeH264Options { @@ -162,567 +91,87 @@ typedef struct VAAPIEncodeH264Options { int low_power; // Entropy encoder type. int coder; + int aud; + int sei; + int profile; + int level; } VAAPIEncodeH264Options; -#define vseq_var(name) vseq->name, name -#define vseq_field(name) vseq->seq_fields.bits.name, name -#define vvui_field(name) vseq->vui_fields.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpic_field(name) vpic->pic_fields.bits.name, name -#define vslice_var(name) vslice->name, name -#define vslice_field(name) vslice->slice_fields.bits.name, name -#define mseq_var(name) mseq->name, name -#define mslice_var(name) mslice->name, name - -static void vaapi_encode_h264_write_nal_header(PutBitContext *pbc, - int nal_unit_type, int nal_ref_idc) -{ - u(1, 0, forbidden_zero_bit); - u(2, nal_ref_idc, nal_ref_idc); - u(5, nal_unit_type, nal_unit_type); -} - -static void vaapi_encode_h264_write_trailing_rbsp(PutBitContext *pbc) -{ - u(1, 1, rbsp_stop_one_bit); - while (put_bits_count(pbc) & 7) - u(1, 0, rbsp_alignment_zero_bit); -} - -static void vaapi_encode_h264_write_vui(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - u(1, vvui_field(aspect_ratio_info_present_flag)); - if (vseq->vui_fields.bits.aspect_ratio_info_present_flag) { - u(8, vseq_var(aspect_ratio_idc)); - if (vseq->aspect_ratio_idc == 255) { - u(16, vseq_var(sar_width)); - u(16, vseq_var(sar_height)); - } - } - - u(1, mseq_var(overscan_info_present_flag)); - if (mseq->overscan_info_present_flag) - u(1, mseq_var(overscan_appropriate_flag)); - - u(1, mseq_var(video_signal_type_present_flag)); - if (mseq->video_signal_type_present_flag) { - u(3, mseq_var(video_format)); - u(1, mseq_var(video_full_range_flag)); - u(1, mseq_var(colour_description_present_flag)); - if (mseq->colour_description_present_flag) { - u(8, mseq_var(colour_primaries)); - u(8, mseq_var(transfer_characteristics)); - u(8, mseq_var(matrix_coefficients)); - } - } - - u(1, mseq_var(chroma_loc_info_present_flag)); - if (mseq->chroma_loc_info_present_flag) { - ue(mseq_var(chroma_sample_loc_type_top_field)); - ue(mseq_var(chroma_sample_loc_type_bottom_field)); - } - - u(1, vvui_field(timing_info_present_flag)); - if (vseq->vui_fields.bits.timing_info_present_flag) { - u(32, vseq_var(num_units_in_tick)); - u(32, vseq_var(time_scale)); - u(1, mseq_var(fixed_frame_rate_flag)); - } - - u(1, mseq_var(nal_hrd_parameters_present_flag)); - if (mseq->nal_hrd_parameters_present_flag) { - ue(mseq_var(cpb_cnt_minus1)); - u(4, mseq_var(bit_rate_scale)); - u(4, mseq_var(cpb_size_scale)); - for (i = 0; i <= mseq->cpb_cnt_minus1; i++) { - ue(mseq_var(bit_rate_value_minus1[i])); - ue(mseq_var(cpb_size_value_minus1[i])); - u(1, mseq_var(cbr_flag[i])); - } - u(5, mseq_var(initial_cpb_removal_delay_length_minus1)); - u(5, mseq_var(cpb_removal_delay_length_minus1)); - u(5, mseq_var(dpb_output_delay_length_minus1)); - u(5, mseq_var(time_offset_length)); - } - u(1, mseq_var(vcl_hrd_parameters_present_flag)); - if (mseq->vcl_hrd_parameters_present_flag) { - av_assert0(0 && "vcl hrd parameters not supported"); - } - - if (mseq->nal_hrd_parameters_present_flag || - mseq->vcl_hrd_parameters_present_flag) - u(1, mseq_var(low_delay_hrd_flag)); - u(1, mseq_var(pic_struct_present_flag)); - - u(1, vvui_field(bitstream_restriction_flag)); - if (vseq->vui_fields.bits.bitstream_restriction_flag) { - u(1, mseq_var(motion_vectors_over_pic_boundaries_flag)); - ue(mseq_var(max_bytes_per_pic_denom)); - ue(mseq_var(max_bits_per_mb_denom)); - ue(vvui_field(log2_max_mv_length_horizontal)); - ue(vvui_field(log2_max_mv_length_vertical)); - ue(mseq_var(max_num_reorder_frames)); - ue(mseq_var(max_dec_pic_buffering)); - } -} - -static void vaapi_encode_h264_write_sps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - vaapi_encode_h264_write_nal_header(pbc, H264_NAL_SPS, 3); - - u(8, mseq_var(profile_idc)); - u(1, mseq_var(constraint_set0_flag)); - u(1, mseq_var(constraint_set1_flag)); - u(1, mseq_var(constraint_set2_flag)); - u(1, mseq_var(constraint_set3_flag)); - u(1, mseq_var(constraint_set4_flag)); - u(1, mseq_var(constraint_set5_flag)); - u(2, 0, reserved_zero_2bits); - - u(8, vseq_var(level_idc)); - - ue(vseq_var(seq_parameter_set_id)); - - if (mseq->profile_idc == 100 || mseq->profile_idc == 110 || - mseq->profile_idc == 122 || mseq->profile_idc == 244 || - mseq->profile_idc == 44 || mseq->profile_idc == 83 || - mseq->profile_idc == 86 || mseq->profile_idc == 118 || - mseq->profile_idc == 128 || mseq->profile_idc == 138) { - ue(vseq_field(chroma_format_idc)); - - if (vseq->seq_fields.bits.chroma_format_idc == 3) - u(1, mseq_var(separate_colour_plane_flag)); - - ue(vseq_var(bit_depth_luma_minus8)); - ue(vseq_var(bit_depth_chroma_minus8)); - - u(1, mseq_var(qpprime_y_zero_transform_bypass_flag)); - - u(1, vseq_field(seq_scaling_matrix_present_flag)); - if (vseq->seq_fields.bits.seq_scaling_matrix_present_flag) { - av_assert0(0 && "scaling matrices not supported"); - } - } - - ue(vseq_field(log2_max_frame_num_minus4)); - ue(vseq_field(pic_order_cnt_type)); - - if (vseq->seq_fields.bits.pic_order_cnt_type == 0) { - ue(vseq_field(log2_max_pic_order_cnt_lsb_minus4)); - } else if (vseq->seq_fields.bits.pic_order_cnt_type == 1) { - u(1, mseq_var(delta_pic_order_always_zero_flag)); - se(vseq_var(offset_for_non_ref_pic)); - se(vseq_var(offset_for_top_to_bottom_field)); - ue(vseq_var(num_ref_frames_in_pic_order_cnt_cycle)); - - for (i = 0; i < vseq->num_ref_frames_in_pic_order_cnt_cycle; i++) - se(vseq_var(offset_for_ref_frame[i])); - } - - ue(vseq_var(max_num_ref_frames)); - u(1, mseq_var(gaps_in_frame_num_allowed_flag)); - - ue(vseq->picture_width_in_mbs - 1, pic_width_in_mbs_minus1); - ue(vseq->picture_height_in_mbs - 1, pic_height_in_mbs_minus1); - - u(1, vseq_field(frame_mbs_only_flag)); - if (!vseq->seq_fields.bits.frame_mbs_only_flag) - u(1, vseq_field(mb_adaptive_frame_field_flag)); - - u(1, vseq_field(direct_8x8_inference_flag)); - - u(1, vseq_var(frame_cropping_flag)); - if (vseq->frame_cropping_flag) { - ue(vseq_var(frame_crop_left_offset)); - ue(vseq_var(frame_crop_right_offset)); - ue(vseq_var(frame_crop_top_offset)); - ue(vseq_var(frame_crop_bottom_offset)); - } - - u(1, vseq_var(vui_parameters_present_flag)); - if (vseq->vui_parameters_present_flag) - vaapi_encode_h264_write_vui(pbc, ctx); - - vaapi_encode_h264_write_trailing_rbsp(pbc); -} - -static void vaapi_encode_h264_write_pps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - - vaapi_encode_h264_write_nal_header(pbc, H264_NAL_PPS, 3); - - ue(vpic_var(pic_parameter_set_id)); - ue(vpic_var(seq_parameter_set_id)); - - u(1, vpic_field(entropy_coding_mode_flag)); - u(1, mseq_var(bottom_field_pic_order_in_frame_present_flag)); - - ue(mseq_var(num_slice_groups_minus1)); - if (mseq->num_slice_groups_minus1 > 0) { - ue(mseq_var(slice_group_map_type)); - av_assert0(0 && "slice groups not supported"); - } - - ue(vpic_var(num_ref_idx_l0_active_minus1)); - ue(vpic_var(num_ref_idx_l1_active_minus1)); - - u(1, vpic_field(weighted_pred_flag)); - u(2, vpic_field(weighted_bipred_idc)); - - se(vpic->pic_init_qp - 26, pic_init_qp_minus26); - se(mseq_var(pic_init_qs_minus26)); - se(vpic_var(chroma_qp_index_offset)); - - u(1, vpic_field(deblocking_filter_control_present_flag)); - u(1, vpic_field(constrained_intra_pred_flag)); - u(1, vpic_field(redundant_pic_cnt_present_flag)); - u(1, vpic_field(transform_8x8_mode_flag)); - - u(1, vpic_field(pic_scaling_matrix_present_flag)); - if (vpic->pic_fields.bits.pic_scaling_matrix_present_flag) { - av_assert0(0 && "scaling matrices not supported"); - } - - se(vpic_var(second_chroma_qp_index_offset)); - - vaapi_encode_h264_write_trailing_rbsp(pbc); -} - -static void vaapi_encode_h264_write_slice_header2(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice) -{ - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH264Slice *pslice = slice->priv_data; - VAAPIEncodeH264MiscSliceParams *mslice = &pslice->misc_slice_params; - - vaapi_encode_h264_write_nal_header(pbc, mslice->nal_unit_type, - mslice->nal_ref_idc); - - ue(vslice->macroblock_address, first_mb_in_slice); - ue(vslice_var(slice_type)); - ue(vpic_var(pic_parameter_set_id)); - - if (mseq->separate_colour_plane_flag) { - u(2, mslice_var(colour_plane_id)); - } - - u(4 + vseq->seq_fields.bits.log2_max_frame_num_minus4, - (vpic->frame_num & - ((1 << (4 + vseq->seq_fields.bits.log2_max_frame_num_minus4)) - 1)), - frame_num); - - if (!vseq->seq_fields.bits.frame_mbs_only_flag) { - u(1, mslice_var(field_pic_flag)); - if (mslice->field_pic_flag) - u(1, mslice_var(bottom_field_flag)); - } - - if (vpic->pic_fields.bits.idr_pic_flag) { - ue(vslice_var(idr_pic_id)); - } - - if (vseq->seq_fields.bits.pic_order_cnt_type == 0) { - u(4 + vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4, - vslice_var(pic_order_cnt_lsb)); - if (mseq->bottom_field_pic_order_in_frame_present_flag && - !mslice->field_pic_flag) { - se(vslice_var(delta_pic_order_cnt_bottom)); - } - } - - if (vseq->seq_fields.bits.pic_order_cnt_type == 1 && - !vseq->seq_fields.bits.delta_pic_order_always_zero_flag) { - se(vslice_var(delta_pic_order_cnt[0])); - if (mseq->bottom_field_pic_order_in_frame_present_flag && - !mslice->field_pic_flag) { - se(vslice_var(delta_pic_order_cnt[1])); - } - } - - if (vpic->pic_fields.bits.redundant_pic_cnt_present_flag) { - ue(mslice_var(redundant_pic_cnt)); - } - - if (vslice->slice_type == SLICE_TYPE_B) { - u(1, vslice_var(direct_spatial_mv_pred_flag)); - } - - if (vslice->slice_type == SLICE_TYPE_P || - vslice->slice_type == SLICE_TYPE_SP || - vslice->slice_type == SLICE_TYPE_B) { - u(1, vslice_var(num_ref_idx_active_override_flag)); - if (vslice->num_ref_idx_active_override_flag) { - ue(vslice_var(num_ref_idx_l0_active_minus1)); - if (vslice->slice_type == SLICE_TYPE_B) - ue(vslice_var(num_ref_idx_l1_active_minus1)); - } - } - - if (mslice->nal_unit_type == 20 || mslice->nal_unit_type == 21) { - av_assert0(0 && "no MVC support"); - } else { - if (vslice->slice_type % 5 != 2 && vslice->slice_type % 5 != 4) { - u(1, mslice_var(ref_pic_list_modification_flag_l0)); - if (mslice->ref_pic_list_modification_flag_l0) { - av_assert0(0 && "ref pic list modification"); - } - } - if (vslice->slice_type % 5 == 1) { - u(1, mslice_var(ref_pic_list_modification_flag_l1)); - if (mslice->ref_pic_list_modification_flag_l1) { - av_assert0(0 && "ref pic list modification"); - } - } - } - - if ((vpic->pic_fields.bits.weighted_pred_flag && - (vslice->slice_type == SLICE_TYPE_P || - vslice->slice_type == SLICE_TYPE_SP)) || - (vpic->pic_fields.bits.weighted_bipred_idc == 1 && - vslice->slice_type == SLICE_TYPE_B)) { - av_assert0(0 && "prediction weights not supported"); - } - - av_assert0(mslice->nal_ref_idc > 0 == - vpic->pic_fields.bits.reference_pic_flag); - if (mslice->nal_ref_idc != 0) { - if (vpic->pic_fields.bits.idr_pic_flag) { - u(1, mslice_var(no_output_of_prior_pics_flag)); - u(1, mslice_var(long_term_reference_flag)); - } else { - u(1, mslice_var(adaptive_ref_pic_marking_mode_flag)); - if (mslice->adaptive_ref_pic_marking_mode_flag) { - av_assert0(0 && "MMCOs not supported"); - } - } - } - - if (vpic->pic_fields.bits.entropy_coding_mode_flag && - vslice->slice_type != SLICE_TYPE_I && - vslice->slice_type != SLICE_TYPE_SI) { - ue(vslice_var(cabac_init_idc)); - } - - se(vslice_var(slice_qp_delta)); - if (vslice->slice_type == SLICE_TYPE_SP || - vslice->slice_type == SLICE_TYPE_SI) { - if (vslice->slice_type == SLICE_TYPE_SP) - u(1, mslice_var(sp_for_switch_flag)); - se(mslice_var(slice_qs_delta)); - } - - if (vpic->pic_fields.bits.deblocking_filter_control_present_flag) { - ue(vslice_var(disable_deblocking_filter_idc)); - if (vslice->disable_deblocking_filter_idc != 1) { - se(vslice_var(slice_alpha_c0_offset_div2)); - se(vslice_var(slice_beta_offset_div2)); - } - } - - if (mseq->num_slice_groups_minus1 > 0 && - mseq->slice_group_map_type >= 3 && mseq->slice_group_map_type <= 5) { - av_assert0(0 && "slice groups not supported"); - } - - // No alignment - this need not be a byte boundary. -} - -static void vaapi_encode_h264_write_buffering_period(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - int i; - - ue(vpic_var(seq_parameter_set_id)); - - if (mseq->nal_hrd_parameters_present_flag) { - for (i = 0; i <= mseq->cpb_cnt_minus1; i++) { - u(mseq->initial_cpb_removal_delay_length_minus1 + 1, - mseq_var(initial_cpb_removal_delay)); - u(mseq->initial_cpb_removal_delay_length_minus1 + 1, - mseq_var(initial_cpb_removal_delay_offset)); - } - } - if (mseq->vcl_hrd_parameters_present_flag) { - av_assert0(0 && "vcl hrd parameters not supported"); - } -} - -static void vaapi_encode_h264_write_pic_timing(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i, num_clock_ts; - - if (mseq->nal_hrd_parameters_present_flag || - mseq->vcl_hrd_parameters_present_flag) { - u(mseq->cpb_removal_delay_length_minus1 + 1, - 2 * vseq->num_units_in_tick * priv->cpb_delay, - cpb_removal_delay); - u(mseq->dpb_output_delay_length_minus1 + 1, - 2 * vseq->num_units_in_tick * priv->dpb_delay, - dpb_output_delay); - } - if (mseq->pic_struct_present_flag) { - u(4, mseq_var(pic_struct)); - num_clock_ts = (mseq->pic_struct <= 2 ? 1 : - mseq->pic_struct <= 4 ? 2 : - mseq->pic_struct <= 8 ? 3 : 0); - for (i = 0; i < num_clock_ts; i++) { - u(1, 0, clock_timestamp_flag[i]); - // No full timestamp information. - } - } -} - -static void vaapi_encode_h264_write_identifier(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - const char *lavc = LIBAVCODEC_IDENT; - const char *vaapi = VA_VERSION_S; - const char *driver = vaQueryVendorString(ctx->hwctx->display); - char tmp[256]; - int i; - - // Random (version 4) ISO 11578 UUID. - uint8_t uuid[16] = { - 0x59, 0x94, 0x8b, 0x28, 0x11, 0xec, 0x45, 0xaf, - 0x96, 0x75, 0x19, 0xd4, 0x1f, 0xea, 0xa9, 0x4d, - }; - - for (i = 0; i < 16; i++) - u(8, uuid[i], uuid_iso_iec_11578); - - snprintf(tmp, sizeof(tmp), "%s / VAAPI %s / %s", lavc, vaapi, driver); - for (i = 0; i < sizeof(tmp) && tmp[i]; i++) - u(8, tmp[i], user_data_payload_byte); -} - -static void vaapi_encode_h264_write_sei(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) +static int vaapi_encode_h264_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) { + VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; - PutBitContext payload_bits; - char payload[256]; - int payload_type, payload_size, i; - void (*write_payload)(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) = NULL; + int err; - vaapi_encode_h264_write_nal_header(pbc, H264_NAL_SEI, 0); - - for (payload_type = 0; payload_type < 64; payload_type++) { - switch (payload_type) { - case H264_SEI_TYPE_BUFFERING_PERIOD: - if (!priv->send_timing_sei || - pic->type != PICTURE_TYPE_IDR) - continue; - write_payload = &vaapi_encode_h264_write_buffering_period; - break; - case H264_SEI_TYPE_PIC_TIMING: - if (!priv->send_timing_sei) - continue; - write_payload = &vaapi_encode_h264_write_pic_timing; - break; - case H264_SEI_TYPE_USER_DATA_UNREGISTERED: - if (pic->encode_order != 0) - continue; - write_payload = &vaapi_encode_h264_write_identifier; - break; - default: - continue; - } - - init_put_bits(&payload_bits, payload, sizeof(payload)); - write_payload(&payload_bits, ctx, pic); - if (put_bits_count(&payload_bits) & 7) { - write_u(&payload_bits, 1, 1, bit_equal_to_one); - while (put_bits_count(&payload_bits) & 7) - write_u(&payload_bits, 1, 0, bit_equal_to_zero); - } - payload_size = put_bits_count(&payload_bits) / 8; - flush_put_bits(&payload_bits); - - u(8, payload_type, last_payload_type_byte); - u(8, payload_size, last_payload_size_byte); - for (i = 0; i < payload_size; i++) - u(8, payload[i] & 0xff, sei_payload); + err = ff_cbs_write_fragment_data(priv->cbc, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; } - vaapi_encode_h264_write_trailing_rbsp(pbc); + if (*data_len < 8 * au->data_size - au->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * au->data_size - au->data_bit_padding); + return AVERROR(ENOSPC); + } + + memcpy(data, au->data, au->data_size); + *data_len = 8 * au->data_size - au->data_bit_padding; + + return 0; +} + +static int vaapi_encode_h264_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + H264RawNALUnitHeader *header = nal_unit; + int err; + + err = ff_cbs_insert_unit_content(priv->cbc, au, -1, + header->nal_unit_type, nal_unit); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: " + "type = %d.\n", header->nal_unit_type); + return err; + } + + return 0; } static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; int err; - size_t nal_len, bit_len, bit_pos, next_len; - bit_len = *data_len; - bit_pos = 0; + if (priv->aud_needed) { + err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; + } - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_sps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->sps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_pps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->pps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - *data_len = bit_pos; - return 0; + err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } static int vaapi_encode_h264_write_slice_header(AVCodecContext *avctx, @@ -730,18 +179,26 @@ static int vaapi_encode_h264_write_slice_header(AVCodecContext *avctx, VAAPIEncodeSlice *slice, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_slice_header2(&pbc, ctx, pic, slice); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + if (priv->aud_needed) { + err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; + } - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->slice); + if (err < 0) + goto fail; + + err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, @@ -749,253 +206,487 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, int index, int *type, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err, i; - if (index == 0 && ctx->va_rc_mode == VA_RC_CBR) { + if (priv->sei_needed) { + if (priv->aud_needed) { + err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; + } + + memset(&priv->sei, 0, sizeof(priv->sei)); + priv->sei.nal_unit_header.nal_unit_type = H264_NAL_SEI; + + i = 0; + if (pic->encode_order == 0 && opt->sei & SEI_IDENTIFIER) { + priv->sei.payload[i].payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED; + priv->sei.payload[i].payload.user_data_unregistered = priv->identifier; + ++i; + } + if (opt->sei & SEI_TIMING) { + if (pic->type == PICTURE_TYPE_IDR) { + priv->sei.payload[i].payload_type = H264_SEI_TYPE_BUFFERING_PERIOD; + priv->sei.payload[i].payload.buffering_period = priv->buffering_period; + ++i; + } + priv->sei.payload[i].payload_type = H264_SEI_TYPE_PIC_TIMING; + priv->sei.payload[i].payload.pic_timing = priv->pic_timing; + ++i; + } + if (opt->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { + priv->sei.payload[i].payload_type = H264_SEI_TYPE_RECOVERY_POINT; + priv->sei.payload[i].payload.recovery_point = priv->recovery_point; + ++i; + } + + priv->sei.payload_count = i; + av_assert0(priv->sei.payload_count > 0); + + err = vaapi_encode_h264_add_nal(avctx, au, &priv->sei); + if (err < 0) + goto fail; + priv->sei_needed = 0; + + err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); + if (err < 0) + goto fail; + + ff_cbs_fragment_uninit(priv->cbc, au); + + *type = VAEncPackedHeaderRawData; + return 0; + +#if !CONFIG_VAAPI_1 + } else if (priv->sei_cbr_workaround_needed) { + // Insert a zero-length header using the old SEI type. This is + // required to avoid triggering broken behaviour on Intel platforms + // in CBR mode where an invalid SEI message is generated by the + // driver and inserted into the stream. + *data_len = 0; *type = VAEncPackedHeaderH264_SEI; - - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_sei(&pbc, ctx, pic); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); + priv->sei_cbr_workaround_needed = 0; + return 0; +#endif } else { return AVERROR_EOF; } + +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH264Options *opt = - (VAAPIEncodeH264Options*)ctx->codec_options_data; - int i; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; + H264RawSPS *sps = &priv->sps; + H264RawPPS *pps = &priv->pps; + VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; + VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - { - vseq->seq_parameter_set_id = 0; + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); - vseq->level_idc = avctx->level; + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); - vseq->max_num_ref_frames = 1 + (avctx->max_b_frames > 0); + sps->nal_unit_header.nal_ref_idc = 3; + sps->nal_unit_header.nal_unit_type = H264_NAL_SPS; - vseq->picture_width_in_mbs = priv->mb_width; - vseq->picture_height_in_mbs = priv->mb_height; + sps->profile_idc = avctx->profile & 0xff; + sps->constraint_set1_flag = + !!(avctx->profile & FF_PROFILE_H264_CONSTRAINED); + sps->constraint_set3_flag = + !!(avctx->profile & FF_PROFILE_H264_INTRA); - vseq->seq_fields.bits.chroma_format_idc = 1; - vseq->seq_fields.bits.frame_mbs_only_flag = 1; - vseq->seq_fields.bits.direct_8x8_inference_flag = 1; - vseq->seq_fields.bits.log2_max_frame_num_minus4 = 4; - vseq->seq_fields.bits.pic_order_cnt_type = 0; - vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = - av_clip(av_log2(avctx->max_b_frames + 1) - 2, 0, 12); + sps->level_idc = avctx->level; - if (avctx->width != ctx->surface_width || - avctx->height != ctx->surface_height) { - vseq->frame_cropping_flag = 1; + sps->seq_parameter_set_id = 0; + sps->chroma_format_idc = 1; - vseq->frame_crop_left_offset = 0; - vseq->frame_crop_right_offset = - (ctx->surface_width - avctx->width) / 2; - vseq->frame_crop_top_offset = 0; - vseq->frame_crop_bottom_offset = - (ctx->surface_height - avctx->height) / 2; - } else { - vseq->frame_cropping_flag = 0; - } + sps->log2_max_frame_num_minus4 = 4; + sps->pic_order_cnt_type = 0; + sps->log2_max_pic_order_cnt_lsb_minus4 = + av_clip(av_log2(ctx->b_per_p + 1) - 2, 0, 12); - vseq->vui_parameters_present_flag = 1; - if (avctx->sample_aspect_ratio.num != 0) { - vseq->vui_fields.bits.aspect_ratio_info_present_flag = 1; - // There is a large enum of these which we could support - // individually rather than using the generic X/Y form? - if (avctx->sample_aspect_ratio.num == - avctx->sample_aspect_ratio.den) { - vseq->aspect_ratio_idc = 1; - } else { - vseq->aspect_ratio_idc = 255; // Extended SAR. - vseq->sar_width = avctx->sample_aspect_ratio.num; - vseq->sar_height = avctx->sample_aspect_ratio.den; + sps->max_num_ref_frames = + (avctx->profile & FF_PROFILE_H264_INTRA) ? 0 : + 1 + (ctx->b_per_p > 0); + + sps->pic_width_in_mbs_minus1 = priv->mb_width - 1; + sps->pic_height_in_map_units_minus1 = priv->mb_height - 1; + + sps->frame_mbs_only_flag = 1; + sps->direct_8x8_inference_flag = 1; + + if (avctx->width != 16 * priv->mb_width || + avctx->height != 16 * priv->mb_height) { + sps->frame_cropping_flag = 1; + + sps->frame_crop_left_offset = 0; + sps->frame_crop_right_offset = + (16 * priv->mb_width - avctx->width) / 2; + sps->frame_crop_top_offset = 0; + sps->frame_crop_bottom_offset = + (16 * priv->mb_height - avctx->height) / 2; + } else { + sps->frame_cropping_flag = 0; + } + + sps->vui_parameters_present_flag = 1; + + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + static const AVRational sar_idc[] = { + { 0, 0 }, + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int i; + for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (avctx->sample_aspect_ratio.num == sar_idc[i].num && + avctx->sample_aspect_ratio.den == sar_idc[i].den) { + sps->vui.aspect_ratio_idc = i; + break; } } + if (i >= FF_ARRAY_ELEMS(sar_idc)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = avctx->sample_aspect_ratio.num; + sps->vui.sar_height = avctx->sample_aspect_ratio.den; + } + sps->vui.aspect_ratio_info_present_flag = 1; + } + + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || + avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + sps->vui.video_signal_type_present_flag = 1; + sps->vui.video_format = 5; // Unspecified. + sps->vui.video_full_range_flag = + avctx->color_range == AVCOL_RANGE_JPEG; + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || avctx->color_trc != AVCOL_TRC_UNSPECIFIED || avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { - mseq->video_signal_type_present_flag = 1; - mseq->video_format = 5; // Unspecified. - mseq->video_full_range_flag = 0; - mseq->colour_description_present_flag = 1; - // These enums are derived from the standard and hence - // we can just use the values directly. - mseq->colour_primaries = avctx->color_primaries; - mseq->transfer_characteristics = avctx->color_trc; - mseq->matrix_coefficients = avctx->colorspace; + sps->vui.colour_description_present_flag = 1; + sps->vui.colour_primaries = avctx->color_primaries; + sps->vui.transfer_characteristics = avctx->color_trc; + sps->vui.matrix_coefficients = avctx->colorspace; } - - vseq->vui_fields.bits.bitstream_restriction_flag = 1; - mseq->motion_vectors_over_pic_boundaries_flag = 1; - mseq->max_bytes_per_pic_denom = 0; - mseq->max_bits_per_mb_denom = 0; - vseq->vui_fields.bits.log2_max_mv_length_horizontal = 16; - vseq->vui_fields.bits.log2_max_mv_length_vertical = 16; - - mseq->max_num_reorder_frames = (avctx->max_b_frames > 0); - mseq->max_dec_pic_buffering = vseq->max_num_ref_frames; - - vseq->bits_per_second = avctx->bit_rate; - - vseq->vui_fields.bits.timing_info_present_flag = 1; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vseq->num_units_in_tick = avctx->framerate.den; - vseq->time_scale = 2 * avctx->framerate.num; - mseq->fixed_frame_rate_flag = 1; - } else { - vseq->num_units_in_tick = avctx->time_base.num; - vseq->time_scale = 2 * avctx->time_base.den; - mseq->fixed_frame_rate_flag = 0; - } - - if (ctx->va_rc_mode == VA_RC_CBR) { - priv->send_timing_sei = 1; - mseq->nal_hrd_parameters_present_flag = 1; - - mseq->cpb_cnt_minus1 = 0; - - // Try to scale these to a sensible range so that the - // golomb encode of the value is not overlong. - mseq->bit_rate_scale = - av_clip_uintp2(av_log2(avctx->bit_rate) - 15 - 6, 4); - mseq->bit_rate_value_minus1[0] = - (avctx->bit_rate >> mseq->bit_rate_scale + 6) - 1; - - mseq->cpb_size_scale = - av_clip_uintp2(av_log2(ctx->hrd_params.hrd.buffer_size) - 15 - 4, 4); - mseq->cpb_size_value_minus1[0] = - (ctx->hrd_params.hrd.buffer_size >> mseq->cpb_size_scale + 4) - 1; - - // CBR mode isn't actually available here, despite naming. - mseq->cbr_flag[0] = 0; - - mseq->initial_cpb_removal_delay_length_minus1 = 23; - mseq->cpb_removal_delay_length_minus1 = 23; - mseq->dpb_output_delay_length_minus1 = 7; - mseq->time_offset_length = 0; - - // This calculation can easily overflow 32 bits. - mseq->initial_cpb_removal_delay = 90000 * - (uint64_t)ctx->hrd_params.hrd.initial_buffer_fullness / - ctx->hrd_params.hrd.buffer_size; - - mseq->initial_cpb_removal_delay_offset = 0; - } else { - priv->send_timing_sei = 0; - mseq->nal_hrd_parameters_present_flag = 0; - } - - vseq->intra_period = avctx->gop_size; - vseq->intra_idr_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + } else { + sps->vui.video_format = 5; + sps->vui.video_full_range_flag = 0; + sps->vui.colour_primaries = avctx->color_primaries; + sps->vui.transfer_characteristics = avctx->color_trc; + sps->vui.matrix_coefficients = avctx->colorspace; } - { - vpic->CurrPic.picture_id = VA_INVALID_ID; - vpic->CurrPic.flags = VA_PICTURE_H264_INVALID; - - for (i = 0; i < FF_ARRAY_ELEMS(vpic->ReferenceFrames); i++) { - vpic->ReferenceFrames[i].picture_id = VA_INVALID_ID; - vpic->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; - } - - vpic->coded_buf = VA_INVALID_ID; - - vpic->pic_parameter_set_id = 0; - vpic->seq_parameter_set_id = 0; - - vpic->num_ref_idx_l0_active_minus1 = 0; - vpic->num_ref_idx_l1_active_minus1 = 0; - - vpic->pic_fields.bits.entropy_coding_mode_flag = - opt->coder ? ((avctx->profile & 0xff) != 66) : 0; - vpic->pic_fields.bits.weighted_pred_flag = 0; - vpic->pic_fields.bits.weighted_bipred_idc = 0; - vpic->pic_fields.bits.transform_8x8_mode_flag = - ((avctx->profile & 0xff) >= 100); - - vpic->pic_init_qp = priv->fixed_qp_idr; + if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { + sps->vui.chroma_loc_info_present_flag = 1; + sps->vui.chroma_sample_loc_type_top_field = + sps->vui.chroma_sample_loc_type_bottom_field = + avctx->chroma_sample_location - 1; } - { - mseq->profile_idc = avctx->profile & 0xff; - - if (avctx->profile & FF_PROFILE_H264_CONSTRAINED) - mseq->constraint_set1_flag = 1; - if (avctx->profile & FF_PROFILE_H264_INTRA) - mseq->constraint_set3_flag = 1; + sps->vui.timing_info_present_flag = 1; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + sps->vui.num_units_in_tick = avctx->framerate.den; + sps->vui.time_scale = 2 * avctx->framerate.num; + sps->vui.fixed_frame_rate_flag = 1; + } else { + sps->vui.num_units_in_tick = avctx->time_base.num; + sps->vui.time_scale = 2 * avctx->time_base.den; + sps->vui.fixed_frame_rate_flag = 0; } + if (opt->sei & SEI_TIMING) { + H264RawHRD *hrd = &sps->vui.nal_hrd_parameters; + + sps->vui.nal_hrd_parameters_present_flag = 1; + + hrd->cpb_cnt_minus1 = 0; + + // Try to scale these to a sensible range so that the + // golomb encode of the value is not overlong. + hrd->bit_rate_scale = + av_clip_uintp2(av_log2(avctx->bit_rate) - 15 - 6, 4); + hrd->bit_rate_value_minus1[0] = + (avctx->bit_rate >> hrd->bit_rate_scale + 6) - 1; + + hrd->cpb_size_scale = + av_clip_uintp2(av_log2(ctx->hrd_params.hrd.buffer_size) - 15 - 4, 4); + hrd->cpb_size_value_minus1[0] = + (ctx->hrd_params.hrd.buffer_size >> hrd->cpb_size_scale + 4) - 1; + + // CBR mode as defined for the HRD cannot be achieved without filler + // data, so this flag cannot be set even with VAAPI CBR modes. + hrd->cbr_flag[0] = 0; + + hrd->initial_cpb_removal_delay_length_minus1 = 23; + hrd->cpb_removal_delay_length_minus1 = 23; + hrd->dpb_output_delay_length_minus1 = 7; + hrd->time_offset_length = 0; + + priv->buffering_period.seq_parameter_set_id = sps->seq_parameter_set_id; + + // This calculation can easily overflow 32 bits. + priv->buffering_period.nal.initial_cpb_removal_delay[0] = 90000 * + (uint64_t)ctx->hrd_params.hrd.initial_buffer_fullness / + ctx->hrd_params.hrd.buffer_size; + priv->buffering_period.nal.initial_cpb_removal_delay_offset[0] = 0; + } else { + sps->vui.nal_hrd_parameters_present_flag = 0; + sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag; + } + + sps->vui.bitstream_restriction_flag = 1; + sps->vui.motion_vectors_over_pic_boundaries_flag = 1; + sps->vui.log2_max_mv_length_horizontal = 16; + sps->vui.log2_max_mv_length_vertical = 16; + sps->vui.max_num_reorder_frames = (ctx->b_per_p > 0); + sps->vui.max_dec_frame_buffering = sps->max_num_ref_frames; + + pps->nal_unit_header.nal_ref_idc = 3; + pps->nal_unit_header.nal_unit_type = H264_NAL_PPS; + + pps->pic_parameter_set_id = 0; + pps->seq_parameter_set_id = 0; + + pps->entropy_coding_mode_flag = + !(sps->profile_idc == FF_PROFILE_H264_BASELINE || + sps->profile_idc == FF_PROFILE_H264_EXTENDED || + sps->profile_idc == FF_PROFILE_H264_CAVLC_444); + if (!opt->coder && pps->entropy_coding_mode_flag) + pps->entropy_coding_mode_flag = 0; + + pps->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; + + pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26; + + if (sps->profile_idc == FF_PROFILE_H264_BASELINE || + sps->profile_idc == FF_PROFILE_H264_EXTENDED || + sps->profile_idc == FF_PROFILE_H264_MAIN) { + pps->more_rbsp_data = 0; + } else { + pps->more_rbsp_data = 1; + + pps->transform_8x8_mode_flag = 1; + } + + *vseq = (VAEncSequenceParameterBufferH264) { + .seq_parameter_set_id = sps->seq_parameter_set_id, + .level_idc = sps->level_idc, + .intra_period = avctx->gop_size, + .intra_idr_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + + .bits_per_second = avctx->bit_rate, + .max_num_ref_frames = sps->max_num_ref_frames, + .picture_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1, + .picture_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1, + + .seq_fields.bits = { + .chroma_format_idc = sps->chroma_format_idc, + .frame_mbs_only_flag = sps->frame_mbs_only_flag, + .mb_adaptive_frame_field_flag = sps->mb_adaptive_frame_field_flag, + .seq_scaling_matrix_present_flag = sps->seq_scaling_matrix_present_flag, + .direct_8x8_inference_flag = sps->direct_8x8_inference_flag, + .log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4, + .pic_order_cnt_type = sps->pic_order_cnt_type, + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4, + .delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag, + }, + + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + + .frame_cropping_flag = sps->frame_cropping_flag, + .frame_crop_left_offset = sps->frame_crop_left_offset, + .frame_crop_right_offset = sps->frame_crop_right_offset, + .frame_crop_top_offset = sps->frame_crop_top_offset, + .frame_crop_bottom_offset = sps->frame_crop_bottom_offset, + + .vui_parameters_present_flag = sps->vui_parameters_present_flag, + + .vui_fields.bits = { + .aspect_ratio_info_present_flag = sps->vui.aspect_ratio_info_present_flag, + .timing_info_present_flag = sps->vui.timing_info_present_flag, + .bitstream_restriction_flag = sps->vui.bitstream_restriction_flag, + .log2_max_mv_length_horizontal = sps->vui.log2_max_mv_length_horizontal, + .log2_max_mv_length_vertical = sps->vui.log2_max_mv_length_vertical, + }, + + .aspect_ratio_idc = sps->vui.aspect_ratio_idc, + .sar_width = sps->vui.sar_width, + .sar_height = sps->vui.sar_height, + .num_units_in_tick = sps->vui.num_units_in_tick, + .time_scale = sps->vui.time_scale, + }; + + *vpic = (VAEncPictureParameterBufferH264) { + .CurrPic = { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_H264_INVALID, + }, + + .coded_buf = VA_INVALID_ID, + + .pic_parameter_set_id = pps->pic_parameter_set_id, + .seq_parameter_set_id = pps->seq_parameter_set_id, + + .pic_init_qp = pps->pic_init_qp_minus26 + 26, + .num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1, + + .chroma_qp_index_offset = pps->chroma_qp_index_offset, + .second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset, + + .pic_fields.bits = { + .entropy_coding_mode_flag = pps->entropy_coding_mode_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_idc = pps->weighted_bipred_idc, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .transform_8x8_mode_flag = pps->transform_8x8_mode_flag, + .deblocking_filter_control_present_flag = + pps->deblocking_filter_control_present_flag, + .redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present_flag, + .pic_order_present_flag = + pps->bottom_field_pic_order_in_frame_present_flag, + .pic_scaling_matrix_present_flag = pps->pic_scaling_matrix_present_flag, + }, + }; + return 0; } static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; + H264RawSPS *sps = &priv->sps; + VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; int i; + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); + if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); - vpic->frame_num = 0; + priv->frame_num = 0; priv->next_frame_num = 1; - priv->cpb_delay = 0; + priv->cpb_delay = 0; priv->last_idr_frame = pic->display_order; + ++priv->idr_pic_count; + + priv->slice_type = 7; + priv->primary_pic_type = 0; } else { - vpic->frame_num = priv->next_frame_num; + priv->frame_num = priv->next_frame_num; + if (pic->type != PICTURE_TYPE_B) { - // nal_ref_idc != 0 - ++priv->next_frame_num; + // Reference picture, so frame_num advances. + priv->next_frame_num = (priv->frame_num + 1) & + ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); } ++priv->cpb_delay; + + if (pic->type == PICTURE_TYPE_I) { + priv->slice_type = 7; + priv->primary_pic_type = 0; + } else if (pic->type == PICTURE_TYPE_P) { + priv->slice_type = 5; + priv->primary_pic_type = 1; + } else { + priv->slice_type = 6; + priv->primary_pic_type = 2; + } } - priv->dpb_delay = pic->display_order - pic->encode_order + 1; + priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; + priv->dpb_delay = pic->display_order - pic->encode_order + 1; - vpic->frame_num = vpic->frame_num & - ((1 << (4 + vseq->seq_fields.bits.log2_max_frame_num_minus4)) - 1); + if (opt->aud) { + priv->aud_needed = 1; + priv->aud.nal_unit_header.nal_unit_type = H264_NAL_AUD; + priv->aud.primary_pic_type = priv->primary_pic_type; + } else { + priv->aud_needed = 0; + } - vpic->CurrPic.picture_id = pic->recon_surface; - vpic->CurrPic.frame_idx = vpic->frame_num; - vpic->CurrPic.flags = 0; - vpic->CurrPic.TopFieldOrderCnt = pic->display_order - priv->last_idr_frame; - vpic->CurrPic.BottomFieldOrderCnt = pic->display_order - priv->last_idr_frame; + if (opt->sei & SEI_IDENTIFIER && pic->encode_order == 0) + priv->sei_needed = 1; +#if !CONFIG_VAAPI_1 + if (ctx->va_rc_mode == VA_RC_CBR) + priv->sei_cbr_workaround_needed = 1; +#endif + + if (opt->sei & SEI_TIMING) { + memset(&priv->pic_timing, 0, sizeof(priv->pic_timing)); + + priv->pic_timing.cpb_removal_delay = 2 * priv->cpb_delay; + priv->pic_timing.dpb_output_delay = 2 * priv->dpb_delay; + + priv->sei_needed = 1; + } + + if (opt->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { + priv->recovery_point.recovery_frame_cnt = 0; + priv->recovery_point.exact_match_flag = 1; + priv->recovery_point.broken_link_flag = ctx->b_per_p > 0; + + priv->sei_needed = 1; + } + + vpic->CurrPic = (VAPictureH264) { + .picture_id = pic->recon_surface, + .frame_idx = priv->frame_num, + .flags = 0, + .TopFieldOrderCnt = priv->pic_order_cnt, + .BottomFieldOrderCnt = priv->pic_order_cnt, + }; for (i = 0; i < pic->nb_refs; i++) { VAAPIEncodePicture *ref = pic->refs[i]; + unsigned int frame_num = (ref->encode_order - priv->last_idr_frame) & + ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); + unsigned int pic_order_cnt = ref->display_order - priv->last_idr_frame; + av_assert0(ref && ref->encode_order < pic->encode_order); - vpic->ReferenceFrames[i].picture_id = ref->recon_surface; - vpic->ReferenceFrames[i].frame_idx = ref->encode_order; - vpic->ReferenceFrames[i].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; - vpic->ReferenceFrames[i].TopFieldOrderCnt = ref->display_order - priv->last_idr_frame; - vpic->ReferenceFrames[i].BottomFieldOrderCnt = ref->display_order - priv->last_idr_frame; + vpic->ReferenceFrames[i] = (VAPictureH264) { + .picture_id = ref->recon_surface, + .frame_idx = frame_num, + .flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE, + .TopFieldOrderCnt = pic_order_cnt, + .BottomFieldOrderCnt = pic_order_cnt, + }; } for (; i < FF_ARRAY_ELEMS(vpic->ReferenceFrames); i++) { - vpic->ReferenceFrames[i].picture_id = VA_INVALID_ID; - vpic->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; + vpic->ReferenceFrames[i] = (VAPictureH264) { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_H264_INVALID, + }; } vpic->coded_buf = pic->output_buffer; - vpic->pic_fields.bits.idr_pic_flag = (pic->type == PICTURE_TYPE_IDR); + vpic->frame_num = priv->frame_num; + + vpic->pic_fields.bits.idr_pic_flag = (pic->type == PICTURE_TYPE_IDR); vpic->pic_fields.bits.reference_pic_flag = (pic->type != PICTURE_TYPE_B); pic->nb_slices = 1; @@ -1007,58 +698,57 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Slice *pslice; - VAAPIEncodeH264MiscSliceParams *mslice; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + H264RawSPS *sps = &priv->sps; + H264RawPPS *pps = &priv->pps; + H264RawSliceHeader *sh = &priv->slice.header; + VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; + VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; int i; - slice->priv_data = av_mallocz(sizeof(*pslice)); - if (!slice->priv_data) - return AVERROR(ENOMEM); - pslice = slice->priv_data; - mslice = &pslice->misc_slice_params; - - if (pic->type == PICTURE_TYPE_IDR) - mslice->nal_unit_type = H264_NAL_IDR_SLICE; - else - mslice->nal_unit_type = H264_NAL_SLICE; - - switch (pic->type) { - case PICTURE_TYPE_IDR: - vslice->slice_type = SLICE_TYPE_I; - mslice->nal_ref_idc = 3; - break; - case PICTURE_TYPE_I: - vslice->slice_type = SLICE_TYPE_I; - mslice->nal_ref_idc = 2; - break; - case PICTURE_TYPE_P: - vslice->slice_type = SLICE_TYPE_P; - mslice->nal_ref_idc = 1; - break; - case PICTURE_TYPE_B: - vslice->slice_type = SLICE_TYPE_B; - mslice->nal_ref_idc = 0; - break; - default: - av_assert0(0 && "invalid picture type"); + if (pic->type == PICTURE_TYPE_IDR) { + sh->nal_unit_header.nal_unit_type = H264_NAL_IDR_SLICE; + sh->nal_unit_header.nal_ref_idc = 3; + } else { + sh->nal_unit_header.nal_unit_type = H264_NAL_SLICE; + sh->nal_unit_header.nal_ref_idc = pic->type != PICTURE_TYPE_B; } // Only one slice per frame. - vslice->macroblock_address = 0; - vslice->num_macroblocks = priv->mb_width * priv->mb_height; + sh->first_mb_in_slice = 0; + sh->slice_type = priv->slice_type; + + sh->pic_parameter_set_id = pps->pic_parameter_set_id; + + sh->frame_num = priv->frame_num; + sh->idr_pic_id = priv->idr_pic_count; + + sh->pic_order_cnt_lsb = priv->pic_order_cnt & + ((1 << (4 + sps->log2_max_pic_order_cnt_lsb_minus4)) - 1); + + sh->direct_spatial_mv_pred_flag = 1; + + if (pic->type == PICTURE_TYPE_B) + sh->slice_qp_delta = priv->fixed_qp_b - (pps->pic_init_qp_minus26 + 26); + else if (pic->type == PICTURE_TYPE_P) + sh->slice_qp_delta = priv->fixed_qp_p - (pps->pic_init_qp_minus26 + 26); + else + sh->slice_qp_delta = priv->fixed_qp_idr - (pps->pic_init_qp_minus26 + 26); + + + vslice->macroblock_address = sh->first_mb_in_slice; + vslice->num_macroblocks = priv->mb_width * priv->mb_height; vslice->macroblock_info = VA_INVALID_ID; - vslice->pic_parameter_set_id = vpic->pic_parameter_set_id; - vslice->idr_pic_id = priv->idr_pic_count++; + vslice->slice_type = sh->slice_type % 5; + vslice->pic_parameter_set_id = sh->pic_parameter_set_id; + vslice->idr_pic_id = sh->idr_pic_id; - vslice->pic_order_cnt_lsb = (pic->display_order - priv->last_idr_frame) & - ((1 << (4 + vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4)) - 1); + vslice->pic_order_cnt_lsb = sh->pic_order_cnt_lsb; + + vslice->direct_spatial_mv_pred_flag = sh->direct_spatial_mv_pred_flag; for (i = 0; i < FF_ARRAY_ELEMS(vslice->RefPicList0); i++) { vslice->RefPicList0[i].picture_id = VA_INVALID_ID; @@ -1072,26 +762,15 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, // Backward reference for P- or B-frame. av_assert0(pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l0_active_minus1 = 0; vslice->RefPicList0[0] = vpic->ReferenceFrames[0]; } if (pic->nb_refs >= 2) { // Forward reference for B-frame. av_assert0(pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l1_active_minus1 = 0; vslice->RefPicList1[0] = vpic->ReferenceFrames[1]; } - if (pic->type == PICTURE_TYPE_B) - vslice->slice_qp_delta = priv->fixed_qp_b - vpic->pic_init_qp; - else if (pic->type == PICTURE_TYPE_P) - vslice->slice_qp_delta = priv->fixed_qp_p - vpic->pic_init_qp; - else - vslice->slice_qp_delta = priv->fixed_qp_idr - vpic->pic_init_qp; - - vslice->direct_spatial_mv_pred_flag = 1; + vslice->slice_qp_delta = sh->slice_qp_delta; return 0; } @@ -1101,6 +780,11 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; VAAPIEncodeH264Options *opt = ctx->codec_options; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_H264, avctx); + if (err < 0) + return err; priv->mb_width = FFALIGN(avctx->width, 16) / 16; priv->mb_height = FFALIGN(avctx->height, 16) / 16; @@ -1118,6 +802,8 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) else priv->fixed_qp_b = priv->fixed_qp_p; + opt->sei &= ~SEI_TIMING; + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " "%d / %d / %d for IDR- / P- / B-frames.\n", priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); @@ -1140,6 +826,34 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) if (avctx->compression_level == FF_COMPRESSION_DEFAULT) avctx->compression_level = opt->quality; + if (opt->sei & SEI_IDENTIFIER) { + const char *lavc = LIBAVCODEC_IDENT; + const char *vaapi = VA_VERSION_S; + const char *driver; + int len; + + memcpy(priv->identifier.uuid_iso_iec_11578, + vaapi_encode_h264_sei_identifier_uuid, + sizeof(priv->identifier.uuid_iso_iec_11578)); + + driver = vaQueryVendorString(ctx->hwctx->display); + if (!driver) + driver = "unknown driver"; + + len = snprintf(NULL, 0, "%s / VAAPI %s / %s", lavc, vaapi, driver); + if (len >= 0) { + priv->identifier_string = av_malloc(len + 1); + if (!priv->identifier_string) + return AVERROR(ENOMEM); + + snprintf(priv->identifier_string, len + 1, + "%s / VAAPI %s / %s", lavc, vaapi, driver); + + priv->identifier.data = priv->identifier_string; + priv->identifier.data_length = len + 1; + } + } + return 0; } @@ -1174,6 +888,11 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) ctx->codec = &vaapi_encode_type_h264; + if (avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = opt->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = opt->level; + switch (avctx->profile) { case FF_PROFILE_H264_BASELINE: av_log(avctx, AV_LOG_WARNING, "H.264 baseline profile is not " @@ -1251,6 +970,19 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_h264_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + + if (priv) { + ff_cbs_close(&priv->cbc); + av_freep(&priv->identifier_string); + } + + return ff_vaapi_encode_close(avctx); +} + #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ offsetof(VAAPIEncodeH264Options, x)) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) @@ -1268,12 +1000,66 @@ static const AVOption vaapi_encode_h264_options[] = { { "cabac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, { "vlc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS, "coder" }, { "ac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, + + { "aud", "Include AUD", + OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + + { "sei", "Set SEI to include", + OFFSET(sei), AV_OPT_TYPE_FLAGS, + { .i64 = SEI_IDENTIFIER | SEI_TIMING | SEI_RECOVERY_POINT }, + 0, INT_MAX, FLAGS, "sei" }, + { "identifier", "Include encoder version identifier", + 0, AV_OPT_TYPE_CONST, { .i64 = SEI_IDENTIFIER }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + { "timing", "Include timing parameters (buffering_period and pic_timing)", + 0, AV_OPT_TYPE_CONST, { .i64 = SEI_TIMING }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + { "recovery_point", "Include recovery points where appropriate", + 0, AV_OPT_TYPE_CONST, { .i64 = SEI_RECOVERY_POINT }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + + { "profile", "Set profile (profile_idc and constraint_set*_flag)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = FF_PROFILE_H264_HIGH }, 0x0000, 0xffff, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("constrained_baseline", FF_PROFILE_H264_CONSTRAINED_BASELINE) }, + { PROFILE("main", FF_PROFILE_H264_MAIN) }, + { PROFILE("high", FF_PROFILE_H264_HIGH) }, +#undef PROFILE + + { "level", "Set level (level_idc)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = 51 }, 0x00, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("1", 10) }, + { LEVEL("1.1", 11) }, + { LEVEL("1.2", 12) }, + { LEVEL("1.3", 13) }, + { LEVEL("2", 20) }, + { LEVEL("2.1", 21) }, + { LEVEL("2.2", 22) }, + { LEVEL("3", 30) }, + { LEVEL("3.1", 31) }, + { LEVEL("3.2", 32) }, + { LEVEL("4", 40) }, + { LEVEL("4.1", 41) }, + { LEVEL("4.2", 42) }, + { LEVEL("5", 50) }, + { LEVEL("5.1", 51) }, + { LEVEL("5.2", 52) }, + { LEVEL("6", 60) }, + { LEVEL("6.1", 61) }, + { LEVEL("6.2", 62) }, +#undef LEVEL + { NULL }, }; static const AVCodecDefault vaapi_encode_h264_defaults[] = { - { "profile", "100" }, - { "level", "51" }, { "b", "0" }, { "bf", "2" }, { "g", "120" }, @@ -1301,12 +1087,13 @@ AVCodec ff_h264_vaapi_encoder = { sizeof(VAAPIEncodeH264Options)), .init = &vaapi_encode_h264_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, + .close = &vaapi_encode_h264_close, .priv_class = &vaapi_encode_h264_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_h264_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 971458db8..f3b4f6c7e 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -16,163 +16,25 @@ * 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/common.h" #include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" +#include "cbs.h" +#include "cbs_h265.h" #include "hevc.h" #include "internal.h" #include "put_bits.h" #include "vaapi_encode.h" -#include "vaapi_encode_h26x.h" -#define MAX_ST_REF_PIC_SETS 32 -#define MAX_DPB_PICS 16 -#define MAX_LAYERS 1 - - -typedef struct VAAPIEncodeH265STRPS { - char inter_ref_pic_set_prediction_flag; - - unsigned int num_negative_pics; - unsigned int num_positive_pics; - - unsigned int delta_poc_s0_minus1[MAX_DPB_PICS]; - char used_by_curr_pic_s0_flag[MAX_DPB_PICS]; - - unsigned int delta_poc_s1_minus1[MAX_DPB_PICS]; - char used_by_curr_pic_s1_flag[MAX_DPB_PICS]; -} VAAPIEncodeH265STRPS; - -// This structure contains all possibly-useful per-sequence syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH265MiscSequenceParams { - - // Parameter set IDs. - unsigned int video_parameter_set_id; - unsigned int seq_parameter_set_id; - - // Layering. - unsigned int vps_max_layers_minus1; - unsigned int vps_max_sub_layers_minus1; - char vps_temporal_id_nesting_flag; - unsigned int vps_max_layer_id; - unsigned int vps_num_layer_sets_minus1; - unsigned int sps_max_sub_layers_minus1; - char sps_temporal_id_nesting_flag; - char layer_id_included_flag[MAX_LAYERS][64]; - - // Profile/tier/level parameters. - char general_profile_compatibility_flag[32]; - char general_progressive_source_flag; - char general_interlaced_source_flag; - char general_non_packed_constraint_flag; - char general_frame_only_constraint_flag; - char general_inbld_flag; - - // Decode/display ordering parameters. - unsigned int log2_max_pic_order_cnt_lsb_minus4; - char vps_sub_layer_ordering_info_present_flag; - unsigned int vps_max_dec_pic_buffering_minus1[MAX_LAYERS]; - unsigned int vps_max_num_reorder_pics[MAX_LAYERS]; - unsigned int vps_max_latency_increase_plus1[MAX_LAYERS]; - char sps_sub_layer_ordering_info_present_flag; - unsigned int sps_max_dec_pic_buffering_minus1[MAX_LAYERS]; - unsigned int sps_max_num_reorder_pics[MAX_LAYERS]; - unsigned int sps_max_latency_increase_plus1[MAX_LAYERS]; - - // Timing information. - char vps_timing_info_present_flag; - unsigned int vps_num_units_in_tick; - unsigned int vps_time_scale; - char vps_poc_proportional_to_timing_flag; - unsigned int vps_num_ticks_poc_diff_minus1; - - // Cropping information. - char conformance_window_flag; - unsigned int conf_win_left_offset; - unsigned int conf_win_right_offset; - unsigned int conf_win_top_offset; - unsigned int conf_win_bottom_offset; - - // Short-term reference picture sets. - unsigned int num_short_term_ref_pic_sets; - VAAPIEncodeH265STRPS st_ref_pic_set[MAX_ST_REF_PIC_SETS]; - - // Long-term reference pictures. - char long_term_ref_pics_present_flag; - unsigned int num_long_term_ref_pics_sps; - struct { - unsigned int lt_ref_pic_poc_lsb_sps; - char used_by_curr_pic_lt_sps_flag; - } lt_ref_pic; - - // Deblocking filter control. - char deblocking_filter_control_present_flag; - char deblocking_filter_override_enabled_flag; - char pps_deblocking_filter_disabled_flag; - int pps_beta_offset_div2; - int pps_tc_offset_div2; - - // Video Usability Information. - char vui_parameters_present_flag; - char aspect_ratio_info_present_flag; - unsigned int aspect_ratio_idc; - unsigned int sar_width; - unsigned int sar_height; - char video_signal_type_present_flag; - unsigned int video_format; - char video_full_range_flag; - char colour_description_present_flag; - unsigned int colour_primaries; - unsigned int transfer_characteristics; - unsigned int matrix_coeffs; - - // Oddments. - char uniform_spacing_flag; - char output_flag_present_flag; - char cabac_init_present_flag; - unsigned int num_extra_slice_header_bits; - char lists_modification_present_flag; - char pps_slice_chroma_qp_offsets_present_flag; - char pps_slice_chroma_offset_list_enabled_flag; -} VAAPIEncodeH265MiscSequenceParams; - -// This structure contains all possibly-useful per-slice syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH265MiscSliceParams { - // Slice segments. - char first_slice_segment_in_pic_flag; - - // Short-term reference picture sets. - char short_term_ref_pic_set_sps_flag; - unsigned int short_term_ref_pic_idx; - VAAPIEncodeH265STRPS st_ref_pic_set; - - // Deblocking filter. - char deblocking_filter_override_flag; - - // Oddments. - char slice_reserved_flag[8]; - char no_output_of_prior_pics_flag; - char pic_output_flag; -} VAAPIEncodeH265MiscSliceParams; - -typedef struct VAAPIEncodeH265Slice { - VAAPIEncodeH265MiscSliceParams misc_slice_params; - - int64_t pic_order_cnt; -} VAAPIEncodeH265Slice; - typedef struct VAAPIEncodeH265Context { - VAAPIEncodeH265MiscSequenceParams misc_sequence_params; - unsigned int ctu_width; unsigned int ctu_height; @@ -180,582 +42,110 @@ typedef struct VAAPIEncodeH265Context { int fixed_qp_p; int fixed_qp_b; - int64_t last_idr_frame; + H265RawAUD aud; + H265RawVPS vps; + H265RawSPS sps; + H265RawPPS pps; + H265RawSlice slice; - // Rate control configuration. - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterRateControl rc; - } rc_params; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterHRD hrd; - } hrd_params; + int64_t last_idr_frame; + int pic_order_cnt; + + int slice_nal_unit; + int slice_type; + int pic_type; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_access_unit; + int aud_needed; } VAAPIEncodeH265Context; typedef struct VAAPIEncodeH265Options { int qp; + int aud; + int profile; + int level; } VAAPIEncodeH265Options; -#define vseq_var(name) vseq->name, name -#define vseq_field(name) vseq->seq_fields.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpic_field(name) vpic->pic_fields.bits.name, name -#define vslice_var(name) vslice->name, name -#define vslice_field(name) vslice->slice_fields.bits.name, name -#define mseq_var(name) mseq->name, name -#define mslice_var(name) mslice->name, name -#define mstrps_var(name) mstrps->name, name - -static void vaapi_encode_h265_write_nal_unit_header(PutBitContext *pbc, - int nal_unit_type) +static int vaapi_encode_h265_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) { - u(1, 0, forbidden_zero_bit); - u(6, nal_unit_type, nal_unit_type); - u(6, 0, nuh_layer_id); - u(3, 1, nuh_temporal_id_plus1); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + int err; + + err = ff_cbs_write_fragment_data(priv->cbc, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } + + if (*data_len < 8 * au->data_size - au->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * au->data_size - au->data_bit_padding); + return AVERROR(ENOSPC); + } + + memcpy(data, au->data, au->data_size); + *data_len = 8 * au->data_size - au->data_bit_padding; + + return 0; } -static void vaapi_encode_h265_write_rbsp_trailing_bits(PutBitContext *pbc) +static int vaapi_encode_h265_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) { - u(1, 1, rbsp_stop_one_bit); - while (put_bits_count(pbc) & 7) - u(1, 0, rbsp_alignment_zero_bit); -} + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + H265RawNALUnitHeader *header = nal_unit; + int err; -static void vaapi_encode_h265_write_profile_tier_level(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int j; - - if (1) { - u(2, 0, general_profile_space); - u(1, vseq_var(general_tier_flag)); - u(5, vseq_var(general_profile_idc)); - - for (j = 0; j < 32; j++) { - u(1, mseq_var(general_profile_compatibility_flag[j])); - } - - u(1, mseq_var(general_progressive_source_flag)); - u(1, mseq_var(general_interlaced_source_flag)); - u(1, mseq_var(general_non_packed_constraint_flag)); - u(1, mseq_var(general_frame_only_constraint_flag)); - - if (0) { - // Not main profile. - // Lots of extra constraint flags. - } else { - // put_bits only handles up to 31 bits. - u(23, 0, general_reserved_zero_43bits); - u(20, 0, general_reserved_zero_43bits); - } - - if (vseq->general_profile_idc >= 1 && vseq->general_profile_idc <= 5) { - u(1, mseq_var(general_inbld_flag)); - } else { - u(1, 0, general_reserved_zero_bit); - } + err = ff_cbs_insert_unit_content(priv->cbc, au, -1, + header->nal_unit_type, nal_unit); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: " + "type = %d.\n", header->nal_unit_type); + return err; } - u(8, vseq_var(general_level_idc)); - - // No sublayers. -} - -static void vaapi_encode_h265_write_vps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i, j; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_VPS); - - u(4, mseq->video_parameter_set_id, vps_video_parameter_set_id); - - u(1, 1, vps_base_layer_internal_flag); - u(1, 1, vps_base_layer_available_flag); - u(6, mseq_var(vps_max_layers_minus1)); - u(3, mseq_var(vps_max_sub_layers_minus1)); - u(1, mseq_var(vps_temporal_id_nesting_flag)); - - u(16, 0xffff, vps_reserved_0xffff_16bits); - - vaapi_encode_h265_write_profile_tier_level(pbc, ctx); - - u(1, mseq_var(vps_sub_layer_ordering_info_present_flag)); - for (i = (mseq->vps_sub_layer_ordering_info_present_flag ? - 0 : mseq->vps_max_sub_layers_minus1); - i <= mseq->vps_max_sub_layers_minus1; i++) { - ue(mseq_var(vps_max_dec_pic_buffering_minus1[i])); - ue(mseq_var(vps_max_num_reorder_pics[i])); - ue(mseq_var(vps_max_latency_increase_plus1[i])); - } - - u(6, mseq_var(vps_max_layer_id)); - ue(mseq_var(vps_num_layer_sets_minus1)); - for (i = 1; i <= mseq->vps_num_layer_sets_minus1; i++) { - for (j = 0; j < mseq->vps_max_layer_id; j++) - u(1, mseq_var(layer_id_included_flag[i][j])); - } - - u(1, mseq_var(vps_timing_info_present_flag)); - if (mseq->vps_timing_info_present_flag) { - u(1, 0, put_bits_hack_zero_bit); - u(31, mseq_var(vps_num_units_in_tick)); - u(1, 0, put_bits_hack_zero_bit); - u(31, mseq_var(vps_time_scale)); - u(1, mseq_var(vps_poc_proportional_to_timing_flag)); - if (mseq->vps_poc_proportional_to_timing_flag) { - ue(mseq_var(vps_num_ticks_poc_diff_minus1)); - } - ue(0, vps_num_hrd_parameters); - } - - u(1, 0, vps_extension_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_st_ref_pic_set(PutBitContext *pbc, - int st_rps_idx, - VAAPIEncodeH265STRPS *mstrps) -{ - int i; - - if (st_rps_idx != 0) - u(1, mstrps_var(inter_ref_pic_set_prediction_flag)); - - if (mstrps->inter_ref_pic_set_prediction_flag) { - av_assert0(0 && "inter ref pic set prediction not supported"); - } else { - ue(mstrps_var(num_negative_pics)); - ue(mstrps_var(num_positive_pics)); - - for (i = 0; i < mstrps->num_negative_pics; i++) { - ue(mstrps_var(delta_poc_s0_minus1[i])); - u(1, mstrps_var(used_by_curr_pic_s0_flag[i])); - } - for (i = 0; i < mstrps->num_positive_pics; i++) { - ue(mstrps_var(delta_poc_s1_minus1[i])); - u(1, mstrps_var(used_by_curr_pic_s1_flag[i])); - } - } -} - -static void vaapi_encode_h265_write_vui_parameters(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - - u(1, mseq_var(aspect_ratio_info_present_flag)); - if (mseq->aspect_ratio_info_present_flag) { - u(8, mseq_var(aspect_ratio_idc)); - if (mseq->aspect_ratio_idc == 255) { - u(16, mseq_var(sar_width)); - u(16, mseq_var(sar_height)); - } - } - - u(1, 0, overscan_info_present_flag); - - u(1, mseq_var(video_signal_type_present_flag)); - if (mseq->video_signal_type_present_flag) { - u(3, mseq_var(video_format)); - u(1, mseq_var(video_full_range_flag)); - u(1, mseq_var(colour_description_present_flag)); - if (mseq->colour_description_present_flag) { - u(8, mseq_var(colour_primaries)); - u(8, mseq_var(transfer_characteristics)); - u(8, mseq_var(matrix_coeffs)); - } - } - - u(1, 0, chroma_loc_info_present_flag); - u(1, 0, neutral_chroma_indication_flag); - u(1, 0, field_seq_flag); - u(1, 0, frame_field_info_present_flag); - u(1, 0, default_display_window_flag); - u(1, 0, vui_timing_info_present_flag); - u(1, 0, bitstream_restriction_flag_flag); -} - -static void vaapi_encode_h265_write_sps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_SPS); - - u(4, mseq->video_parameter_set_id, sps_video_parameter_set_id); - - u(3, mseq_var(sps_max_sub_layers_minus1)); - u(1, mseq_var(sps_temporal_id_nesting_flag)); - - vaapi_encode_h265_write_profile_tier_level(pbc, ctx); - - ue(mseq->seq_parameter_set_id, sps_seq_parameter_set_id); - ue(vseq_field(chroma_format_idc)); - if (vseq->seq_fields.bits.chroma_format_idc == 3) - u(1, 0, separate_colour_plane_flag); - - ue(vseq_var(pic_width_in_luma_samples)); - ue(vseq_var(pic_height_in_luma_samples)); - - u(1, mseq_var(conformance_window_flag)); - if (mseq->conformance_window_flag) { - ue(mseq_var(conf_win_left_offset)); - ue(mseq_var(conf_win_right_offset)); - ue(mseq_var(conf_win_top_offset)); - ue(mseq_var(conf_win_bottom_offset)); - } - - ue(vseq_field(bit_depth_luma_minus8)); - ue(vseq_field(bit_depth_chroma_minus8)); - - ue(mseq_var(log2_max_pic_order_cnt_lsb_minus4)); - - u(1, mseq_var(sps_sub_layer_ordering_info_present_flag)); - for (i = (mseq->sps_sub_layer_ordering_info_present_flag ? - 0 : mseq->sps_max_sub_layers_minus1); - i <= mseq->sps_max_sub_layers_minus1; i++) { - ue(mseq_var(sps_max_dec_pic_buffering_minus1[i])); - ue(mseq_var(sps_max_num_reorder_pics[i])); - ue(mseq_var(sps_max_latency_increase_plus1[i])); - } - - ue(vseq_var(log2_min_luma_coding_block_size_minus3)); - ue(vseq_var(log2_diff_max_min_luma_coding_block_size)); - ue(vseq_var(log2_min_transform_block_size_minus2)); - ue(vseq_var(log2_diff_max_min_transform_block_size)); - ue(vseq_var(max_transform_hierarchy_depth_inter)); - ue(vseq_var(max_transform_hierarchy_depth_intra)); - - u(1, vseq_field(scaling_list_enabled_flag)); - if (vseq->seq_fields.bits.scaling_list_enabled_flag) { - u(1, 0, sps_scaling_list_data_present_flag); - } - - u(1, vseq_field(amp_enabled_flag)); - u(1, vseq_field(sample_adaptive_offset_enabled_flag)); - - u(1, vseq_field(pcm_enabled_flag)); - if (vseq->seq_fields.bits.pcm_enabled_flag) { - u(4, vseq_var(pcm_sample_bit_depth_luma_minus1)); - u(4, vseq_var(pcm_sample_bit_depth_chroma_minus1)); - ue(vseq_var(log2_min_pcm_luma_coding_block_size_minus3)); - ue(vseq->log2_max_pcm_luma_coding_block_size_minus3 - - vseq->log2_min_pcm_luma_coding_block_size_minus3, - log2_diff_max_min_pcm_luma_coding_block_size); - u(1, vseq_field(pcm_loop_filter_disabled_flag)); - } - - ue(mseq_var(num_short_term_ref_pic_sets)); - for (i = 0; i < mseq->num_short_term_ref_pic_sets; i++) - vaapi_encode_h265_write_st_ref_pic_set(pbc, i, - &mseq->st_ref_pic_set[i]); - - u(1, mseq_var(long_term_ref_pics_present_flag)); - if (mseq->long_term_ref_pics_present_flag) { - ue(0, num_long_term_ref_pics_sps); - } - - u(1, vseq_field(sps_temporal_mvp_enabled_flag)); - u(1, vseq_field(strong_intra_smoothing_enabled_flag)); - - u(1, mseq_var(vui_parameters_present_flag)); - if (mseq->vui_parameters_present_flag) { - vaapi_encode_h265_write_vui_parameters(pbc, ctx); - } - - u(1, 0, sps_extension_present_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_pps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_PPS); - - ue(vpic->slice_pic_parameter_set_id, pps_pic_parameter_set_id); - ue(mseq->seq_parameter_set_id, pps_seq_parameter_set_id); - - u(1, vpic_field(dependent_slice_segments_enabled_flag)); - u(1, mseq_var(output_flag_present_flag)); - u(3, mseq_var(num_extra_slice_header_bits)); - u(1, vpic_field(sign_data_hiding_enabled_flag)); - u(1, mseq_var(cabac_init_present_flag)); - - ue(vpic_var(num_ref_idx_l0_default_active_minus1)); - ue(vpic_var(num_ref_idx_l1_default_active_minus1)); - - se(vpic->pic_init_qp - 26, init_qp_minus26); - - u(1, vpic_field(constrained_intra_pred_flag)); - u(1, vpic_field(transform_skip_enabled_flag)); - - u(1, vpic_field(cu_qp_delta_enabled_flag)); - if (vpic->pic_fields.bits.cu_qp_delta_enabled_flag) - ue(vpic_var(diff_cu_qp_delta_depth)); - - se(vpic_var(pps_cb_qp_offset)); - se(vpic_var(pps_cr_qp_offset)); - - u(1, mseq_var(pps_slice_chroma_qp_offsets_present_flag)); - u(1, vpic_field(weighted_pred_flag)); - u(1, vpic_field(weighted_bipred_flag)); - u(1, vpic_field(transquant_bypass_enabled_flag)); - u(1, vpic_field(tiles_enabled_flag)); - u(1, vpic_field(entropy_coding_sync_enabled_flag)); - - if (vpic->pic_fields.bits.tiles_enabled_flag) { - ue(vpic_var(num_tile_columns_minus1)); - ue(vpic_var(num_tile_rows_minus1)); - u(1, mseq_var(uniform_spacing_flag)); - if (!mseq->uniform_spacing_flag) { - for (i = 0; i < vpic->num_tile_columns_minus1; i++) - ue(vpic_var(column_width_minus1[i])); - for (i = 0; i < vpic->num_tile_rows_minus1; i++) - ue(vpic_var(row_height_minus1[i])); - } - u(1, vpic_field(loop_filter_across_tiles_enabled_flag)); - } - - u(1, vpic_field(pps_loop_filter_across_slices_enabled_flag)); - u(1, mseq_var(deblocking_filter_control_present_flag)); - if (mseq->deblocking_filter_control_present_flag) { - u(1, mseq_var(deblocking_filter_override_enabled_flag)); - u(1, mseq_var(pps_deblocking_filter_disabled_flag)); - if (!mseq->pps_deblocking_filter_disabled_flag) { - se(mseq_var(pps_beta_offset_div2)); - se(mseq_var(pps_tc_offset_div2)); - } - } - - u(1, 0, pps_scaling_list_data_present_flag); - // No scaling list data. - - u(1, mseq_var(lists_modification_present_flag)); - ue(vpic_var(log2_parallel_merge_level_minus2)); - u(1, 0, slice_segment_header_extension_present_flag); - u(1, 0, pps_extension_present_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_slice_header2(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH265Slice *pslice = slice->priv_data; - VAAPIEncodeH265MiscSliceParams *mslice = &pslice->misc_slice_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, vpic->nal_unit_type); - - u(1, mslice_var(first_slice_segment_in_pic_flag)); - if (vpic->nal_unit_type >= HEVC_NAL_BLA_W_LP && - vpic->nal_unit_type <= 23) - u(1, mslice_var(no_output_of_prior_pics_flag)); - - ue(vslice_var(slice_pic_parameter_set_id)); - - if (!mslice->first_slice_segment_in_pic_flag) { - if (vpic->pic_fields.bits.dependent_slice_segments_enabled_flag) - u(1, vslice_field(dependent_slice_segment_flag)); - u(av_log2((priv->ctu_width * priv->ctu_height) - 1) + 1, - vslice_var(slice_segment_address)); - } - if (!vslice->slice_fields.bits.dependent_slice_segment_flag) { - for (i = 0; i < mseq->num_extra_slice_header_bits; i++) - u(1, mslice_var(slice_reserved_flag[i])); - - ue(vslice_var(slice_type)); - if (mseq->output_flag_present_flag) - u(1, 1, pic_output_flag); - if (vseq->seq_fields.bits.separate_colour_plane_flag) - u(2, vslice_field(colour_plane_id)); - if (vpic->nal_unit_type != HEVC_NAL_IDR_W_RADL && - vpic->nal_unit_type != HEVC_NAL_IDR_N_LP) { - u(4 + mseq->log2_max_pic_order_cnt_lsb_minus4, - (pslice->pic_order_cnt & - ((1 << (mseq->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1)), - slice_pic_order_cnt_lsb); - - u(1, mslice_var(short_term_ref_pic_set_sps_flag)); - if (!mslice->short_term_ref_pic_set_sps_flag) { - vaapi_encode_h265_write_st_ref_pic_set(pbc, mseq->num_short_term_ref_pic_sets, - &mslice->st_ref_pic_set); - } else if (mseq->num_short_term_ref_pic_sets > 1) { - u(av_log2(mseq->num_short_term_ref_pic_sets - 1) + 1, - mslice_var(short_term_ref_pic_idx)); - } - - if (mseq->long_term_ref_pics_present_flag) { - av_assert0(0); - } - } - - if (vseq->seq_fields.bits.sps_temporal_mvp_enabled_flag) { - u(1, vslice_field(slice_temporal_mvp_enabled_flag)); - } - - if (vseq->seq_fields.bits.sample_adaptive_offset_enabled_flag) { - u(1, vslice_field(slice_sao_luma_flag)); - if (!vseq->seq_fields.bits.separate_colour_plane_flag && - vseq->seq_fields.bits.chroma_format_idc != 0) { - u(1, vslice_field(slice_sao_chroma_flag)); - } - } - - if (vslice->slice_type == HEVC_SLICE_P || vslice->slice_type == HEVC_SLICE_B) { - u(1, vslice_field(num_ref_idx_active_override_flag)); - if (vslice->slice_fields.bits.num_ref_idx_active_override_flag) { - ue(vslice_var(num_ref_idx_l0_active_minus1)); - if (vslice->slice_type == HEVC_SLICE_B) { - ue(vslice_var(num_ref_idx_l1_active_minus1)); - } - } - - if (mseq->lists_modification_present_flag) { - av_assert0(0); - // ref_pic_lists_modification() - } - if (vslice->slice_type == HEVC_SLICE_B) { - u(1, vslice_field(mvd_l1_zero_flag)); - } - if (mseq->cabac_init_present_flag) { - u(1, vslice_field(cabac_init_flag)); - } - if (vslice->slice_fields.bits.slice_temporal_mvp_enabled_flag) { - if (vslice->slice_type == HEVC_SLICE_B) - u(1, vslice_field(collocated_from_l0_flag)); - ue(vpic->collocated_ref_pic_index, collocated_ref_idx); - } - if ((vpic->pic_fields.bits.weighted_pred_flag && - vslice->slice_type == HEVC_SLICE_P) || - (vpic->pic_fields.bits.weighted_bipred_flag && - vslice->slice_type == HEVC_SLICE_B)) { - av_assert0(0); - // pred_weight_table() - } - ue(5 - vslice->max_num_merge_cand, five_minus_max_num_merge_cand); - } - - se(vslice_var(slice_qp_delta)); - if (mseq->pps_slice_chroma_qp_offsets_present_flag) { - se(vslice_var(slice_cb_qp_offset)); - se(vslice_var(slice_cr_qp_offset)); - } - if (mseq->pps_slice_chroma_offset_list_enabled_flag) { - u(1, 0, cu_chroma_qp_offset_enabled_flag); - } - if (mseq->deblocking_filter_override_enabled_flag) { - u(1, mslice_var(deblocking_filter_override_flag)); - } - if (mslice->deblocking_filter_override_flag) { - u(1, vslice_field(slice_deblocking_filter_disabled_flag)); - if (!vslice->slice_fields.bits.slice_deblocking_filter_disabled_flag) { - se(vslice_var(slice_beta_offset_div2)); - se(vslice_var(slice_tc_offset_div2)); - } - } - if (vpic->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag && - (vslice->slice_fields.bits.slice_sao_luma_flag || - vslice->slice_fields.bits.slice_sao_chroma_flag || - vslice->slice_fields.bits.slice_deblocking_filter_disabled_flag)) { - u(1, vslice_field(slice_loop_filter_across_slices_enabled_flag)); - } - - if (vpic->pic_fields.bits.tiles_enabled_flag || - vpic->pic_fields.bits.entropy_coding_sync_enabled_flag) { - // num_entry_point_offsets - } - - if (0) { - // slice_segment_header_extension_length - } - } - - u(1, 1, alignment_bit_equal_to_one); - while (put_bits_count(pbc) & 7) - u(1, 0, alignment_bit_equal_to_zero); + return 0; } static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; int err; - size_t nal_len, bit_len, bit_pos, next_len; - bit_len = *data_len; - bit_pos = 0; + if (priv->aud_needed) { + err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; + } - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_vps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->vps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_sps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->sps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_pps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->pps); if (err < 0) - return err; - bit_pos += next_len; + goto fail; - *data_len = bit_pos; - return 0; + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, @@ -763,195 +153,384 @@ static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, VAAPIEncodeSlice *slice, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_slice_header2(&pbc, ctx, pic, slice); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + if (priv->aud_needed) { + err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; + } - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->slice); + if (err < 0) + goto fail; + + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + H265RawVPS *vps = &priv->vps; + H265RawSPS *sps = &priv->sps; + H265RawPPS *pps = &priv->pps; + H265RawVUI *vui = &sps->vui; + VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; + VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; int i; - { - // general_profile_space == 0. - vseq->general_profile_idc = 1; // Main profile (ctx->codec_profile?) - vseq->general_tier_flag = 0; + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); - vseq->general_level_idc = avctx->level * 3; + memset(vps, 0, sizeof(*vps)); + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); - vseq->intra_period = 0; - vseq->intra_idr_period = 0; - vseq->ip_period = 0; - vseq->pic_width_in_luma_samples = ctx->surface_width; - vseq->pic_height_in_luma_samples = ctx->surface_height; + // VPS - vseq->seq_fields.bits.chroma_format_idc = 1; // 4:2:0. - vseq->seq_fields.bits.separate_colour_plane_flag = 0; - vseq->seq_fields.bits.bit_depth_luma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - vseq->seq_fields.bits.bit_depth_chroma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - // Other misc flags all zero. + vps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_VPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - // These have to come from the capabilities of the encoder. We have - // no way to query it, so just hardcode ones which worked for me... - // CTB size from 8x8 to 32x32. - vseq->log2_min_luma_coding_block_size_minus3 = 0; - vseq->log2_diff_max_min_luma_coding_block_size = 2; - // Transform size from 4x4 to 32x32. - vseq->log2_min_transform_block_size_minus2 = 0; - vseq->log2_diff_max_min_transform_block_size = 3; - // Full transform hierarchy allowed (2-5). - vseq->max_transform_hierarchy_depth_inter = 3; - vseq->max_transform_hierarchy_depth_intra = 3; + vps->vps_video_parameter_set_id = 0; - vseq->vui_parameters_present_flag = 0; + vps->vps_base_layer_internal_flag = 1; + vps->vps_base_layer_available_flag = 1; + vps->vps_max_layers_minus1 = 0; + vps->vps_max_sub_layers_minus1 = 0; + vps->vps_temporal_id_nesting_flag = 1; - vseq->bits_per_second = avctx->bit_rate; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vseq->vui_num_units_in_tick = avctx->framerate.den; - vseq->vui_time_scale = avctx->framerate.num; - } else { - vseq->vui_num_units_in_tick = avctx->time_base.num; - vseq->vui_time_scale = avctx->time_base.den; - } + vps->profile_tier_level = (H265RawProfileTierLevel) { + .general_profile_space = 0, + .general_profile_idc = avctx->profile, + .general_tier_flag = 0, - vseq->intra_period = avctx->gop_size; - vseq->intra_idr_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + .general_progressive_source_flag = 1, + .general_interlaced_source_flag = 0, + .general_non_packed_constraint_flag = 1, + .general_frame_only_constraint_flag = 1, + + .general_level_idc = avctx->level, + }; + vps->profile_tier_level.general_profile_compatibility_flag[avctx->profile & 31] = 1; + + vps->vps_sub_layer_ordering_info_present_flag = 0; + vps->vps_max_dec_pic_buffering_minus1[0] = (ctx->b_per_p > 0) + 1; + vps->vps_max_num_reorder_pics[0] = (ctx->b_per_p > 0); + vps->vps_max_latency_increase_plus1[0] = 0; + + vps->vps_max_layer_id = 0; + vps->vps_num_layer_sets_minus1 = 0; + vps->layer_id_included_flag[0][0] = 1; + + vps->vps_timing_info_present_flag = 1; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + vps->vps_num_units_in_tick = avctx->framerate.den; + vps->vps_time_scale = avctx->framerate.num; + vps->vps_poc_proportional_to_timing_flag = 1; + vps->vps_num_ticks_poc_diff_one_minus1 = 0; + } else { + vps->vps_num_units_in_tick = avctx->time_base.num; + vps->vps_time_scale = avctx->time_base.den; + vps->vps_poc_proportional_to_timing_flag = 0; + } + vps->vps_num_hrd_parameters = 0; + + + // SPS + + sps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_SPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + sps->sps_video_parameter_set_id = vps->vps_video_parameter_set_id; + + sps->sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1; + sps->sps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag; + + sps->profile_tier_level = vps->profile_tier_level; + + sps->sps_seq_parameter_set_id = 0; + + sps->chroma_format_idc = 1; // YUV 4:2:0. + sps->separate_colour_plane_flag = 0; + + sps->pic_width_in_luma_samples = ctx->surface_width; + sps->pic_height_in_luma_samples = ctx->surface_height; + + if (avctx->width != ctx->surface_width || + avctx->height != ctx->surface_height) { + sps->conformance_window_flag = 1; + sps->conf_win_left_offset = 0; + sps->conf_win_right_offset = + (ctx->surface_width - avctx->width) / 2; + sps->conf_win_top_offset = 0; + sps->conf_win_bottom_offset = + (ctx->surface_height - avctx->height) / 2; + } else { + sps->conformance_window_flag = 0; } - { - vpic->decoded_curr_pic.picture_id = VA_INVALID_ID; - vpic->decoded_curr_pic.flags = VA_PICTURE_HEVC_INVALID; + sps->bit_depth_luma_minus8 = + avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; + sps->bit_depth_chroma_minus8 = sps->bit_depth_luma_minus8; - for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) { - vpic->reference_frames[i].picture_id = VA_INVALID_ID; - vpic->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; - } + sps->log2_max_pic_order_cnt_lsb_minus4 = 8; - vpic->collocated_ref_pic_index = 0xff; - - vpic->last_picture = 0; - - vpic->pic_init_qp = priv->fixed_qp_idr; - - vpic->diff_cu_qp_delta_depth = 0; - vpic->pps_cb_qp_offset = 0; - vpic->pps_cr_qp_offset = 0; - - // tiles_enabled_flag == 0, so ignore num_tile_(rows|columns)_minus1. - - vpic->log2_parallel_merge_level_minus2 = 0; - - // No limit on size. - vpic->ctu_max_bitsize_allowed = 0; - - vpic->num_ref_idx_l0_default_active_minus1 = 0; - vpic->num_ref_idx_l1_default_active_minus1 = 0; - - vpic->slice_pic_parameter_set_id = 0; - - vpic->pic_fields.bits.screen_content_flag = 0; - vpic->pic_fields.bits.enable_gpu_weighted_prediction = 0; - - // Per-CU QP changes are required for non-constant-QP modes. - vpic->pic_fields.bits.cu_qp_delta_enabled_flag = - ctx->va_rc_mode != VA_RC_CQP; + sps->sps_sub_layer_ordering_info_present_flag = + vps->vps_sub_layer_ordering_info_present_flag; + for (i = 0; i <= sps->sps_max_sub_layers_minus1; i++) { + sps->sps_max_dec_pic_buffering_minus1[i] = + vps->vps_max_dec_pic_buffering_minus1[i]; + sps->sps_max_num_reorder_pics[i] = + vps->vps_max_num_reorder_pics[i]; + sps->sps_max_latency_increase_plus1[i] = + vps->vps_max_latency_increase_plus1[i]; } - { - mseq->video_parameter_set_id = 5; - mseq->seq_parameter_set_id = 5; + // These have to come from the capabilities of the encoder. We have no + // way to query them, so just hardcode parameters which work on the Intel + // driver. + // CTB size from 8x8 to 32x32. + sps->log2_min_luma_coding_block_size_minus3 = 0; + sps->log2_diff_max_min_luma_coding_block_size = 2; + // Transform size from 4x4 to 32x32. + sps->log2_min_luma_transform_block_size_minus2 = 0; + sps->log2_diff_max_min_luma_transform_block_size = 3; + // Full transform hierarchy allowed (2-5). + sps->max_transform_hierarchy_depth_inter = 3; + sps->max_transform_hierarchy_depth_intra = 3; + // AMP works. + sps->amp_enabled_flag = 1; + // SAO and temporal MVP do not work. + sps->sample_adaptive_offset_enabled_flag = 0; + sps->sps_temporal_mvp_enabled_flag = 0; - mseq->vps_max_layers_minus1 = 0; - mseq->vps_max_sub_layers_minus1 = 0; - mseq->vps_temporal_id_nesting_flag = 1; - mseq->sps_max_sub_layers_minus1 = 0; - mseq->sps_temporal_id_nesting_flag = 1; + sps->pcm_enabled_flag = 0; - for (i = 0; i < 32; i++) { - mseq->general_profile_compatibility_flag[i] = - (i == vseq->general_profile_idc); - } + // STRPSs should ideally be here rather than defined individually in + // each slice, but the structure isn't completely fixed so for now + // don't bother. + sps->num_short_term_ref_pic_sets = 0; + sps->long_term_ref_pics_present_flag = 0; - mseq->general_progressive_source_flag = 1; - mseq->general_interlaced_source_flag = 0; - mseq->general_non_packed_constraint_flag = 0; - mseq->general_frame_only_constraint_flag = 1; - mseq->general_inbld_flag = 0; + sps->vui_parameters_present_flag = 1; - mseq->log2_max_pic_order_cnt_lsb_minus4 = 8; - mseq->vps_sub_layer_ordering_info_present_flag = 0; - mseq->vps_max_dec_pic_buffering_minus1[0] = (avctx->max_b_frames > 0) + 1; - mseq->vps_max_num_reorder_pics[0] = (avctx->max_b_frames > 0); - mseq->vps_max_latency_increase_plus1[0] = 0; - mseq->sps_sub_layer_ordering_info_present_flag = 0; - mseq->sps_max_dec_pic_buffering_minus1[0] = (avctx->max_b_frames > 0) + 1; - mseq->sps_max_num_reorder_pics[0] = (avctx->max_b_frames > 0); - mseq->sps_max_latency_increase_plus1[0] = 0; - - mseq->vps_timing_info_present_flag = 1; - mseq->vps_num_units_in_tick = avctx->time_base.num; - mseq->vps_time_scale = avctx->time_base.den; - mseq->vps_poc_proportional_to_timing_flag = 1; - mseq->vps_num_ticks_poc_diff_minus1 = 0; - - if (avctx->width != ctx->surface_width || - avctx->height != ctx->surface_height) { - mseq->conformance_window_flag = 1; - mseq->conf_win_left_offset = 0; - mseq->conf_win_right_offset = - (ctx->surface_width - avctx->width) / 2; - mseq->conf_win_top_offset = 0; - mseq->conf_win_bottom_offset = - (ctx->surface_height - avctx->height) / 2; - } else { - mseq->conformance_window_flag = 0; - } - - mseq->num_short_term_ref_pic_sets = 0; - // STRPSs should ideally be here rather than repeated in each slice. - - mseq->vui_parameters_present_flag = 1; - if (avctx->sample_aspect_ratio.num != 0) { - mseq->aspect_ratio_info_present_flag = 1; - if (avctx->sample_aspect_ratio.num == - avctx->sample_aspect_ratio.den) { - mseq->aspect_ratio_idc = 1; - } else { - mseq->aspect_ratio_idc = 255; // Extended SAR. - mseq->sar_width = avctx->sample_aspect_ratio.num; - mseq->sar_height = avctx->sample_aspect_ratio.den; + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + static const AVRational sar_idc[] = { + { 0, 0 }, + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int i; + for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (avctx->sample_aspect_ratio.num == sar_idc[i].num && + avctx->sample_aspect_ratio.den == sar_idc[i].den) { + vui->aspect_ratio_idc = i; + break; } } - if (1) { - // Should this be conditional on some of these being set? - mseq->video_signal_type_present_flag = 1; - mseq->video_format = 5; // Unspecified. - mseq->video_full_range_flag = 0; - mseq->colour_description_present_flag = 1; - mseq->colour_primaries = avctx->color_primaries; - mseq->transfer_characteristics = avctx->color_trc; - mseq->matrix_coeffs = avctx->colorspace; + if (i >= FF_ARRAY_ELEMS(sar_idc)) { + vui->aspect_ratio_idc = 255; + vui->sar_width = avctx->sample_aspect_ratio.num; + vui->sar_height = avctx->sample_aspect_ratio.den; } + vui->aspect_ratio_info_present_flag = 1; } + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || + avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + vui->video_signal_type_present_flag = 1; + vui->video_format = 5; // Unspecified. + vui->video_full_range_flag = + avctx->color_range == AVCOL_RANGE_JPEG; + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + vui->colour_description_present_flag = 1; + vui->colour_primaries = avctx->color_primaries; + vui->transfer_characteristics = avctx->color_trc; + vui->matrix_coefficients = avctx->colorspace; + } + } else { + vui->video_format = 5; + vui->video_full_range_flag = 0; + vui->colour_primaries = avctx->color_primaries; + vui->transfer_characteristics = avctx->color_trc; + vui->matrix_coefficients = avctx->colorspace; + } + + if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { + vui->chroma_loc_info_present_flag = 1; + vui->chroma_sample_loc_type_top_field = + vui->chroma_sample_loc_type_bottom_field = + avctx->chroma_sample_location - 1; + } + + vui->vui_timing_info_present_flag = 1; + vui->vui_num_units_in_tick = vps->vps_num_units_in_tick; + vui->vui_time_scale = vps->vps_time_scale; + vui->vui_poc_proportional_to_timing_flag = vps->vps_poc_proportional_to_timing_flag; + vui->vui_num_ticks_poc_diff_one_minus1 = vps->vps_num_ticks_poc_diff_one_minus1; + vui->vui_hrd_parameters_present_flag = 0; + + vui->bitstream_restriction_flag = 1; + vui->motion_vectors_over_pic_boundaries_flag = 1; + vui->restricted_ref_pic_lists_flag = 1; + vui->max_bytes_per_pic_denom = 0; + vui->max_bits_per_min_cu_denom = 0; + vui->log2_max_mv_length_horizontal = 15; + vui->log2_max_mv_length_vertical = 15; + + + // PPS + + pps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_PPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + pps->pps_pic_parameter_set_id = 0; + pps->pps_seq_parameter_set_id = sps->sps_seq_parameter_set_id; + + pps->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; + + pps->init_qp_minus26 = priv->fixed_qp_idr - 26; + + pps->cu_qp_delta_enabled_flag = (ctx->va_rc_mode != VA_RC_CQP); + pps->diff_cu_qp_delta_depth = 0; + + pps->pps_loop_filter_across_slices_enabled_flag = 1; + + + // Fill VAAPI parameter buffers. + + *vseq = (VAEncSequenceParameterBufferHEVC) { + .general_profile_idc = vps->profile_tier_level.general_profile_idc, + .general_level_idc = vps->profile_tier_level.general_level_idc, + .general_tier_flag = vps->profile_tier_level.general_tier_flag, + + .intra_period = avctx->gop_size, + .intra_idr_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + .bits_per_second = avctx->bit_rate, + + .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, + .pic_height_in_luma_samples = sps->pic_height_in_luma_samples, + + .seq_fields.bits = { + .chroma_format_idc = sps->chroma_format_idc, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + .scaling_list_enabled_flag = sps->scaling_list_enabled_flag, + .strong_intra_smoothing_enabled_flag = + sps->strong_intra_smoothing_enabled_flag, + .amp_enabled_flag = sps->amp_enabled_flag, + .sample_adaptive_offset_enabled_flag = + sps->sample_adaptive_offset_enabled_flag, + .pcm_enabled_flag = sps->pcm_enabled_flag, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag, + .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + }, + + .log2_min_luma_coding_block_size_minus3 = + sps->log2_min_luma_coding_block_size_minus3, + .log2_diff_max_min_luma_coding_block_size = + sps->log2_diff_max_min_luma_coding_block_size, + .log2_min_transform_block_size_minus2 = + sps->log2_min_luma_transform_block_size_minus2, + .log2_diff_max_min_transform_block_size = + sps->log2_diff_max_min_luma_transform_block_size, + .max_transform_hierarchy_depth_inter = + sps->max_transform_hierarchy_depth_inter, + .max_transform_hierarchy_depth_intra = + sps->max_transform_hierarchy_depth_intra, + + .pcm_sample_bit_depth_luma_minus1 = + sps->pcm_sample_bit_depth_luma_minus1, + .pcm_sample_bit_depth_chroma_minus1 = + sps->pcm_sample_bit_depth_chroma_minus1, + .log2_min_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3, + .log2_max_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3 + + sps->log2_diff_max_min_pcm_luma_coding_block_size, + + .vui_parameters_present_flag = 0, + }; + + *vpic = (VAEncPictureParameterBufferHEVC) { + .decoded_curr_pic = { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_HEVC_INVALID, + }, + + .coded_buf = VA_INVALID_ID, + + .collocated_ref_pic_index = 0xff, + + .last_picture = 0, + + .pic_init_qp = pps->init_qp_minus26 + 26, + .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, + .pps_cb_qp_offset = pps->pps_cb_qp_offset, + .pps_cr_qp_offset = pps->pps_cr_qp_offset, + + .num_tile_columns_minus1 = pps->num_tile_columns_minus1, + .num_tile_rows_minus1 = pps->num_tile_rows_minus1, + + .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2, + .ctu_max_bitsize_allowed = 0, + + .num_ref_idx_l0_default_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_default_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1, + + .slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id, + + .pic_fields.bits = { + .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, + .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_flag = pps->weighted_bipred_flag, + .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag, + .tiles_enabled_flag = pps->tiles_enabled_flag, + .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, + .loop_filter_across_tiles_enabled_flag = + pps->loop_filter_across_tiles_enabled_flag, + .scaling_list_data_present_flag = (sps->sps_scaling_list_data_present_flag | + pps->pps_scaling_list_data_present_flag), + .screen_content_flag = 0, + .enable_gpu_weighted_prediction = 0, + .no_output_of_prior_pics_flag = 0, + }, + }; + return 0; } @@ -959,65 +538,104 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Options *opt = ctx->codec_options; + VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; int i; if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); + priv->last_idr_frame = pic->display_order; + + priv->slice_nal_unit = HEVC_NAL_IDR_W_RADL; + priv->slice_type = HEVC_SLICE_I; + priv->pic_type = 0; } else { av_assert0(pic->encode_order > priv->last_idr_frame); - // Display order need not be if we have RA[SD]L pictures, though. + + if (pic->type == PICTURE_TYPE_I) { + priv->slice_nal_unit = HEVC_NAL_CRA_NUT; + priv->slice_type = HEVC_SLICE_I; + priv->pic_type = 0; + } else if (pic->type == PICTURE_TYPE_P) { + av_assert0(pic->refs[0]); + priv->slice_nal_unit = HEVC_NAL_TRAIL_R; + priv->slice_type = HEVC_SLICE_P; + priv->pic_type = 1; + } else { + av_assert0(pic->refs[0] && pic->refs[1]); + if (pic->refs[1]->type == PICTURE_TYPE_I) + priv->slice_nal_unit = HEVC_NAL_RASL_N; + else + priv->slice_nal_unit = HEVC_NAL_TRAIL_N; + priv->slice_type = HEVC_SLICE_B; + priv->pic_type = 2; + } + } + priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; + + if (opt->aud) { + priv->aud_needed = 1; + priv->aud.nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_AUD, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + priv->aud.pic_type = priv->pic_type; + } else { + priv->aud_needed = 0; } - vpic->decoded_curr_pic.picture_id = pic->recon_surface; - vpic->decoded_curr_pic.pic_order_cnt = - pic->display_order - priv->last_idr_frame; - vpic->decoded_curr_pic.flags = 0; + vpic->decoded_curr_pic = (VAPictureHEVC) { + .picture_id = pic->recon_surface, + .pic_order_cnt = priv->pic_order_cnt, + .flags = 0, + }; for (i = 0; i < pic->nb_refs; i++) { VAAPIEncodePicture *ref = pic->refs[i]; - av_assert0(ref); - vpic->reference_frames[i].picture_id = ref->recon_surface; - vpic->reference_frames[i].pic_order_cnt = - ref->display_order - priv->last_idr_frame; - vpic->reference_frames[i].flags = - (ref->display_order < pic->display_order ? - VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | - (ref->display_order > pic->display_order ? - VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0); + av_assert0(ref && ref->encode_order < pic->encode_order); + + vpic->reference_frames[i] = (VAPictureHEVC) { + .picture_id = ref->recon_surface, + .pic_order_cnt = ref->display_order - priv->last_idr_frame, + .flags = (ref->display_order < pic->display_order ? + VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | + (ref->display_order > pic->display_order ? + VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0), + }; } for (; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) { - vpic->reference_frames[i].picture_id = VA_INVALID_ID; - vpic->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; + vpic->reference_frames[i] = (VAPictureHEVC) { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_HEVC_INVALID, + }; } vpic->coded_buf = pic->output_buffer; + vpic->nal_unit_type = priv->slice_nal_unit; + switch (pic->type) { case PICTURE_TYPE_IDR: - vpic->nal_unit_type = HEVC_NAL_IDR_W_RADL; - vpic->pic_fields.bits.idr_pic_flag = 1; - vpic->pic_fields.bits.coding_type = 1; + vpic->pic_fields.bits.idr_pic_flag = 1; + vpic->pic_fields.bits.coding_type = 1; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_I: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 1; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 1; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_P: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 2; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 2; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_B: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 3; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 3; vpic->pic_fields.bits.reference_pic_flag = 0; break; default: @@ -1034,90 +652,40 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, VAAPIEncodeSlice *slice) { VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + const H265RawSPS *sps = &priv->sps; + const H265RawPPS *pps = &priv->pps; + H265RawSliceHeader *sh = &priv->slice.header; VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265Slice *pslice; - VAAPIEncodeH265MiscSliceParams *mslice; int i; - slice->priv_data = av_mallocz(sizeof(*pslice)); - if (!slice->priv_data) - return AVERROR(ENOMEM); - pslice = slice->priv_data; - mslice = &pslice->misc_slice_params; + sh->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = priv->slice_nal_unit, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + sh->slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id; // Currently we only support one slice per frame. - vslice->slice_segment_address = 0; - vslice->num_ctu_in_slice = priv->ctu_width * priv->ctu_height; + sh->first_slice_segment_in_pic_flag = 1; + sh->slice_segment_address = 0; - switch (pic->type) { - case PICTURE_TYPE_IDR: - case PICTURE_TYPE_I: - vslice->slice_type = HEVC_SLICE_I; - break; - case PICTURE_TYPE_P: - vslice->slice_type = HEVC_SLICE_P; - break; - case PICTURE_TYPE_B: - vslice->slice_type = HEVC_SLICE_B; - break; - default: - av_assert0(0 && "invalid picture type"); - } + sh->slice_type = priv->slice_type; - vslice->slice_pic_parameter_set_id = vpic->slice_pic_parameter_set_id; + sh->slice_pic_order_cnt_lsb = priv->pic_order_cnt & + (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1; - pslice->pic_order_cnt = pic->display_order - priv->last_idr_frame; - - for (i = 0; i < FF_ARRAY_ELEMS(vslice->ref_pic_list0); i++) { - vslice->ref_pic_list0[i].picture_id = VA_INVALID_ID; - vslice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; - vslice->ref_pic_list1[i].picture_id = VA_INVALID_ID; - vslice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; - } - - av_assert0(pic->nb_refs <= 2); - if (pic->nb_refs >= 1) { - // Backward reference for P- or B-frame. - av_assert0(pic->type == PICTURE_TYPE_P || - pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l0_active_minus1 = 0; - vslice->ref_pic_list0[0] = vpic->reference_frames[0]; - } - if (pic->nb_refs >= 2) { - // Forward reference for B-frame. - av_assert0(pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l1_active_minus1 = 0; - vslice->ref_pic_list1[0] = vpic->reference_frames[1]; - } - - vslice->max_num_merge_cand = 5; - - if (pic->type == PICTURE_TYPE_B) - vslice->slice_qp_delta = priv->fixed_qp_b - vpic->pic_init_qp; - else if (pic->type == PICTURE_TYPE_P) - vslice->slice_qp_delta = priv->fixed_qp_p - vpic->pic_init_qp; - else - vslice->slice_qp_delta = priv->fixed_qp_idr - vpic->pic_init_qp; - - vslice->slice_fields.bits.last_slice_of_pic_flag = 1; - - mslice->first_slice_segment_in_pic_flag = 1; - - if (pic->type == PICTURE_TYPE_IDR) { - // No reference pictures. - } else if (0) { - mslice->short_term_ref_pic_set_sps_flag = 1; - mslice->short_term_ref_pic_idx = 0; - } else { + if (pic->type != PICTURE_TYPE_IDR) { + H265RawSTRefPicSet *rps; VAAPIEncodePicture *st; int used; - mslice->short_term_ref_pic_set_sps_flag = 0; - mslice->st_ref_pic_set.inter_ref_pic_set_prediction_flag = 0; + sh->short_term_ref_pic_set_sps_flag = 0; + + rps = &sh->short_term_ref_pic_set; + memset(rps, 0, sizeof(*rps)); for (st = ctx->pic_start; st; st = st->next) { if (st->encode_order >= pic->encode_order) { @@ -1130,28 +698,111 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, used = 1; } if (!used) { - // Currently true, but need not be. - continue; + // Usually each picture always uses all of the others in the + // DPB as references. The one case we have to treat here is + // a non-IDR IRAP picture, which may need to hold unused + // references across itself to be used for the decoding of + // following RASL pictures. This looks for such an RASL + // picture, and keeps the reference if there is one. + VAAPIEncodePicture *rp; + for (rp = ctx->pic_start; rp; rp = rp->next) { + if (rp->encode_order < pic->encode_order) + continue; + if (rp->type != PICTURE_TYPE_B) + continue; + if (rp->refs[0] == st && rp->refs[1] == pic) + break; + } + if (!rp) + continue; } // This only works for one instance of each (delta_poc_sN_minus1 // is relative to the previous frame in the list, not relative to // the current frame directly). if (st->display_order < pic->display_order) { - i = mslice->st_ref_pic_set.num_negative_pics; - mslice->st_ref_pic_set.delta_poc_s0_minus1[i] = + rps->delta_poc_s0_minus1[rps->num_negative_pics] = pic->display_order - st->display_order - 1; - mslice->st_ref_pic_set.used_by_curr_pic_s0_flag[i] = used; - ++mslice->st_ref_pic_set.num_negative_pics; + rps->used_by_curr_pic_s0_flag[rps->num_negative_pics] = used; + ++rps->num_negative_pics; } else { - i = mslice->st_ref_pic_set.num_positive_pics; - mslice->st_ref_pic_set.delta_poc_s1_minus1[i] = + rps->delta_poc_s1_minus1[rps->num_positive_pics] = st->display_order - pic->display_order - 1; - mslice->st_ref_pic_set.used_by_curr_pic_s1_flag[i] = used; - ++mslice->st_ref_pic_set.num_positive_pics; + rps->used_by_curr_pic_s1_flag[rps->num_positive_pics] = used; + ++rps->num_positive_pics; } } + + sh->num_long_term_sps = 0; + sh->num_long_term_pics = 0; + + sh->slice_temporal_mvp_enabled_flag = + sps->sps_temporal_mvp_enabled_flag; + if (sh->slice_temporal_mvp_enabled_flag) { + sh->collocated_from_l0_flag = sh->slice_type == HEVC_SLICE_B; + sh->collocated_ref_idx = 0; + } + + sh->num_ref_idx_active_override_flag = 0; + sh->num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1; + sh->num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1; } + sh->slice_sao_luma_flag = sh->slice_sao_chroma_flag = + sps->sample_adaptive_offset_enabled_flag; + + if (pic->type == PICTURE_TYPE_B) + sh->slice_qp_delta = priv->fixed_qp_b - (pps->init_qp_minus26 + 26); + else if (pic->type == PICTURE_TYPE_P) + sh->slice_qp_delta = priv->fixed_qp_p - (pps->init_qp_minus26 + 26); + else + sh->slice_qp_delta = priv->fixed_qp_idr - (pps->init_qp_minus26 + 26); + + + *vslice = (VAEncSliceParameterBufferHEVC) { + .slice_segment_address = sh->slice_segment_address, + .num_ctu_in_slice = priv->ctu_width * priv->ctu_height, + + .slice_type = sh->slice_type, + .slice_pic_parameter_set_id = sh->slice_pic_parameter_set_id, + + .num_ref_idx_l0_active_minus1 = sh->num_ref_idx_l0_active_minus1, + .num_ref_idx_l1_active_minus1 = sh->num_ref_idx_l1_active_minus1, + .ref_pic_list0[0] = vpic->reference_frames[0], + .ref_pic_list1[0] = vpic->reference_frames[1], + + .luma_log2_weight_denom = sh->luma_log2_weight_denom, + .delta_chroma_log2_weight_denom = sh->delta_chroma_log2_weight_denom, + + .max_num_merge_cand = 5 - sh->five_minus_max_num_merge_cand, + + .slice_qp_delta = sh->slice_qp_delta, + .slice_cb_qp_offset = sh->slice_cb_qp_offset, + .slice_cr_qp_offset = sh->slice_cr_qp_offset, + + .slice_beta_offset_div2 = sh->slice_beta_offset_div2, + .slice_tc_offset_div2 = sh->slice_tc_offset_div2, + + .slice_fields.bits = { + .last_slice_of_pic_flag = 1, + .dependent_slice_segment_flag = sh->dependent_slice_segment_flag, + .colour_plane_id = sh->colour_plane_id, + .slice_temporal_mvp_enabled_flag = + sh->slice_temporal_mvp_enabled_flag, + .slice_sao_luma_flag = sh->slice_sao_luma_flag, + .slice_sao_chroma_flag = sh->slice_sao_chroma_flag, + .num_ref_idx_active_override_flag = + sh->num_ref_idx_active_override_flag, + .mvd_l1_zero_flag = sh->mvd_l1_zero_flag, + .cabac_init_flag = sh->cabac_init_flag, + .slice_deblocking_filter_disabled_flag = + sh->slice_deblocking_filter_disabled_flag, + .slice_loop_filter_across_slices_enabled_flag = + sh->slice_loop_filter_across_slices_enabled_flag, + .collocated_from_l0_flag = sh->collocated_from_l0_flag, + }, + }; + + return 0; } @@ -1160,6 +811,11 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; VAAPIEncodeH265Options *opt = ctx->codec_options; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_HEVC, avctx); + if (err < 0) + return err; priv->ctu_width = FFALIGN(ctx->surface_width, 32) / 32; priv->ctu_height = FFALIGN(ctx->surface_height, 32) / 32; @@ -1226,10 +882,17 @@ static const VAAPIEncodeType vaapi_encode_type_h265 = { static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Options *opt = + (VAAPIEncodeH265Options*)ctx->codec_options_data; ctx->codec = &vaapi_encode_type_h265; + if (avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = opt->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = opt->level; + switch (avctx->profile) { case FF_PROFILE_HEVC_MAIN: case FF_PROFILE_UNKNOWN: @@ -1271,18 +934,62 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + + if (priv) + ff_cbs_close(&priv->cbc); + + return ff_vaapi_encode_close(avctx); +} + #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ offsetof(VAAPIEncodeH265Options, x)) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h265_options[] = { { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, 52, FLAGS }, + + { "aud", "Include AUD", + OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + + { "profile", "Set profile (general_profile_idc)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = FF_PROFILE_HEVC_MAIN }, 0x00, 0xff, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("main", FF_PROFILE_HEVC_MAIN) }, + { PROFILE("main10", FF_PROFILE_HEVC_MAIN_10) }, +#undef PROFILE + + { "level", "Set level (general_level_idc)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = 153 }, 0x00, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("1", 30) }, + { LEVEL("2", 60) }, + { LEVEL("2.1", 63) }, + { LEVEL("3", 90) }, + { LEVEL("3.1", 93) }, + { LEVEL("4", 120) }, + { LEVEL("4.1", 123) }, + { LEVEL("5", 150) }, + { LEVEL("5.1", 153) }, + { LEVEL("5.2", 156) }, + { LEVEL("6", 180) }, + { LEVEL("6.1", 183) }, + { LEVEL("6.2", 186) }, +#undef LEVEL + { NULL }, }; static const AVCodecDefault vaapi_encode_h265_defaults[] = { - { "profile", "1" }, - { "level", "51" }, { "b", "0" }, { "bf", "2" }, { "g", "120" }, @@ -1309,12 +1016,13 @@ AVCodec ff_hevc_vaapi_encoder = { sizeof(VAAPIEncodeH265Options)), .init = &vaapi_encode_h265_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, + .close = &vaapi_encode_h265_close, .priv_class = &vaapi_encode_h265_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_h265_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_h26x.c b/libavcodec/vaapi_encode_h26x.c deleted file mode 100644 index d806f9b52..000000000 --- a/libavcodec/vaapi_encode_h26x.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 "vaapi_encode_h26x.h" - -int ff_vaapi_encode_h26x_nal_unit_to_byte_stream(uint8_t *dst, size_t *dst_bit_len, - uint8_t *src, size_t src_bit_len) -{ - size_t dp, sp; - int zero_run = 0; - size_t dst_len = *dst_bit_len / 8; - size_t src_len = (src_bit_len + 7) / 8; - int trailing_zeroes = src_len * 8 - src_bit_len; - - if (dst_len < src_len + 4) { - // Definitely doesn't fit. - goto fail; - } - - // Start code. - dst[0] = dst[1] = dst[2] = 0; - dst[3] = 1; - dp = 4; - - for (sp = 0; sp < src_len; sp++) { - if (dp >= dst_len) - goto fail; - if (zero_run < 2) { - if (src[sp] == 0) - ++zero_run; - else - zero_run = 0; - } else { - if ((src[sp] & ~3) == 0) { - // emulation_prevention_three_byte - dst[dp++] = 3; - if (dp >= dst_len) - goto fail; - } - zero_run = src[sp] == 0; - } - dst[dp++] = src[sp]; - } - - *dst_bit_len = 8 * dp - trailing_zeroes; - return 0; - -fail: - *dst_bit_len = 0; - return AVERROR(ENOSPC); -} diff --git a/libavcodec/vaapi_encode_h26x.h b/libavcodec/vaapi_encode_h26x.h deleted file mode 100644 index f8c6e13ad..000000000 --- a/libavcodec/vaapi_encode_h26x.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_ENCODE_H26X_H -#define AVCODEC_VAAPI_ENCODE_H26X_H - -#include -#include - -#include "golomb.h" -#include "put_bits.h" - - -// Debug code may be interested in the name of the syntax element being -// for tracing purposes. Here, it is just discarded. - -#define write_u(pbc, width, value, name) put_bits(pbc, width, value) -#define write_ue(pbc, value, name) set_ue_golomb(pbc, value) -#define write_se(pbc, value, name) set_se_golomb(pbc, value) - -#define u(width, ...) write_u(pbc, width, __VA_ARGS__) -#define ue(...) write_ue(pbc, __VA_ARGS__) -#define se(...) write_se(pbc, __VA_ARGS__) - - -// Copy from src to dst, applying emulation prevention. -int ff_vaapi_encode_h26x_nal_unit_to_byte_stream(uint8_t *dst, size_t *dst_len, - uint8_t *src, size_t src_len); - -#endif /* AVCODEC_VAAPI_ENCODE_H26X_H */ diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index 2cbf7925f..c949e8964 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -422,9 +422,11 @@ AVCodec ff_mjpeg_vaapi_encoder = { .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_mjpeg_class, + .capabilities = AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_mjpeg_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index dc918884e..4537955c4 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -20,15 +20,11 @@ #include #include "libavutil/avassert.h" -#include "libavutil/common.h" -#include "libavutil/internal.h" -#include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" -#include "internal.h" -#include "mpegvideo.h" -#include "put_bits.h" +#include "cbs.h" +#include "cbs_mpeg2.h" +#include "mpeg12.h" #include "vaapi_encode.h" typedef struct VAAPIEncodeMPEG2Context { @@ -39,79 +35,104 @@ typedef struct VAAPIEncodeMPEG2Context { int quant_p; int quant_b; + MPEG2RawSequenceHeader sequence_header; + MPEG2RawExtensionData sequence_extension; + MPEG2RawExtensionData sequence_display_extension; + MPEG2RawGroupOfPicturesHeader gop_header; + MPEG2RawPictureHeader picture_header; + MPEG2RawExtensionData picture_coding_extension; + int64_t last_i_frame; unsigned int bit_rate; unsigned int vbv_buffer_size; + + AVRational frame_rate; + + unsigned int f_code_horizontal; + unsigned int f_code_vertical; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_fragment; } VAAPIEncodeMPEG2Context; -#define vseq_var(name) vseq->name, name -#define vseqext_field(name) vseq->sequence_extension.bits.name, name -#define vgop_field(name) vseq->gop_header.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpcext_field(name) vpic->picture_coding_extension.bits.name, name -#define vcomp_field(name) vpic->composite_display.bits.name, name +static int vaapi_encode_mpeg2_write_fragment(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *frag) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int err; -#define u2(width, value, name) put_bits(&pbc, width, value) -#define u(width, ...) u2(width, __VA_ARGS__) + err = ff_cbs_write_fragment_data(priv->cbc, frag); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } + + if (*data_len < 8 * frag->data_size - frag->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * frag->data_size - frag->data_bit_padding); + return AVERROR(ENOSPC); + } + + memcpy(data, frag->data, frag->data_size); + *data_len = 8 * frag->data_size - frag->data_bit_padding; + + return 0; +} + +static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, + CodedBitstreamFragment *frag, + int type, void *header) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int err; + + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add header: " + "type = %d.\n", type); + return err; + } + + return 0; +} static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; - PutBitContext pbc; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + CodedBitstreamFragment *frag = &priv->current_fragment; + int err; - init_put_bits(&pbc, data, 8 * *data_len); + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_SEQUENCE_HEADER, + &priv->sequence_header); + if (err < 0) + goto fail; - u(32, SEQ_START_CODE, sequence_header_code); + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION, + &priv->sequence_extension); + if (err < 0) + goto fail; - u(12, vseq->picture_width, horizontal_size_value); - u(12, vseq->picture_height, vertical_size_value); - u(4, vseq_var(aspect_ratio_information)); - u(4, 8, frame_rate_code); - u(18, priv->bit_rate & 0x3fff, bit_rate_value); - u(1, 1, marker_bit); - u(10, priv->vbv_buffer_size & 0x3ff, vbv_buffer_size_value); - u(1, 0, constrained_parameters_flag); - u(1, 0, load_intra_quantiser_matrix); - // intra_quantiser_matrix[64] - u(1, 0, load_non_intra_quantiser_matrix); - // non_intra_quantiser_matrix[64] + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION, + &priv->sequence_display_extension); + if (err < 0) + goto fail; - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - u(32, EXT_START_CODE, extension_start_code); - u(4, 1, extension_start_code_identifier); - u(8, vseqext_field(profile_and_level_indication)); - u(1, vseqext_field(progressive_sequence)); - u(2, vseqext_field(chroma_format)); - u(2, 0, horizontal_size_extension); - u(2, 0, vertical_size_extension); - u(12, priv->bit_rate >> 18, bit_rate_extension); - u(1, 1, marker_bit); - u(8, priv->vbv_buffer_size >> 10, vbv_buffer_size_extension); - u(1, vseqext_field(low_delay)); - u(2, vseqext_field(frame_rate_extension_n)); - u(2, vseqext_field(frame_rate_extension_d)); - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - u(32, GOP_START_CODE, group_start_code); - u(25, vgop_field(time_code)); - u(1, vgop_field(closed_gop)); - u(1, vgop_field(broken_link)); - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - *data_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_GROUP, + &priv->gop_header); + if (err < 0) + goto fail; + err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); +fail: + ff_cbs_fragment_uninit(priv->cbc, frag); return 0; } @@ -119,139 +140,275 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, char *data, size_t *data_len) { - VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; - int picture_coding_type; - PutBitContext pbc; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + CodedBitstreamFragment *frag = &priv->current_fragment; + int err; - init_put_bits(&pbc, data, 8 * *data_len); + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_PICTURE, + &priv->picture_header); + if (err < 0) + goto fail; - u(32, PICTURE_START_CODE, picture_start_code); - u(10, vpic_var(temporal_reference)); - - switch (vpic->picture_type) { - case VAEncPictureTypeIntra: - picture_coding_type = AV_PICTURE_TYPE_I; - break; - case VAEncPictureTypePredictive: - picture_coding_type = AV_PICTURE_TYPE_P; - break; - case VAEncPictureTypeBidirectional: - picture_coding_type = AV_PICTURE_TYPE_B; - break; - default: - av_assert0(0 && "invalid picture_coding_type"); - } - u(3, picture_coding_type, picture_coding_type); - u(16, 0xffff, vbv_delay); - if (picture_coding_type == 2 || picture_coding_type == 3) { - u(1, 0, full_pel_forward_vector); - u(3, 7, forward_f_code); - } - if (picture_coding_type == 3) { - u(1, 0, full_pel_backward_vector); - u(3, 7, backward_f_code); - } - u(1, 0, extra_bit_picture); - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - u(32, EXT_START_CODE, extension_start_code); - u(4, 8, extension_start_code_identifier); - u(4, vpic_var(f_code[0][0])); - u(4, vpic_var(f_code[0][1])); - u(4, vpic_var(f_code[1][0])); - u(4, vpic_var(f_code[1][1])); - u(2, vpcext_field(intra_dc_precision)); - u(2, vpcext_field(picture_structure)); - u(1, vpcext_field(top_field_first)); - u(1, vpcext_field(frame_pred_frame_dct)); - u(1, vpcext_field(concealment_motion_vectors)); - u(1, vpcext_field(q_scale_type)); - u(1, vpcext_field(intra_vlc_format)); - u(1, vpcext_field(alternate_scan)); - u(1, vpcext_field(repeat_first_field)); - u(1, 1, chroma_420_type); - u(1, vpcext_field(progressive_frame)); - u(1, vpcext_field(composite_display_flag)); - if (vpic->picture_coding_extension.bits.composite_display_flag) { - u(1, vcomp_field(v_axis)); - u(3, vcomp_field(field_sequence)); - u(1, vcomp_field(sub_carrier)); - u(7, vcomp_field(burst_amplitude)); - u(8, vcomp_field(sub_carrier_phase)); - } - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - *data_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION, + &priv->picture_coding_extension); + if (err < 0) + goto fail; + err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); +fail: + ff_cbs_fragment_uninit(priv->cbc, frag); return 0; } static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + MPEG2RawSequenceHeader *sh = &priv->sequence_header; + MPEG2RawSequenceExtension *se = &priv->sequence_extension.data.sequence; + MPEG2RawSequenceDisplayExtension *sde = &priv->sequence_display_extension.data.sequence_display; + MPEG2RawGroupOfPicturesHeader *goph = &priv->gop_header; + MPEG2RawPictureHeader *ph = &priv->picture_header; + MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferMPEG2 *vpic = ctx->codec_picture_params; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int code, ext_n, ext_d; - vseq->intra_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + memset(sh, 0, sizeof(*sh)); + memset(se, 0, sizeof(*se)); + memset(sde, 0, sizeof(*sde)); + memset(goph, 0, sizeof(*goph)); + memset(ph, 0, sizeof(*ph)); + memset(pce, 0, sizeof(*pce)); - vseq->picture_width = avctx->width; - vseq->picture_height = avctx->height; - vseq->bits_per_second = avctx->bit_rate; + if (avctx->bit_rate > 0) { + priv->bit_rate = (avctx->bit_rate + 399) / 400; + } else { + // Unknown (not a bitrate-targetting mode), so just use the + // highest value. + priv->bit_rate = 0x3fffffff; + } + if (avctx->rc_buffer_size > 0) { + priv->vbv_buffer_size = (avctx->rc_buffer_size + (1 << 14) - 1) >> 14; + } else { + // Unknown, so guess a value from the bitrate. + priv->vbv_buffer_size = priv->bit_rate >> 14; + } + + switch (avctx->level) { + case 4: // High. + case 6: // High 1440. + priv->f_code_horizontal = 9; + priv->f_code_vertical = 5; + break; + case 8: // Main. + priv->f_code_horizontal = 8; + priv->f_code_vertical = 5; + break; + case 10: // Low. + default: + priv->f_code_horizontal = 7; + priv->f_code_vertical = 4; + break; + } + + + // Sequence header + + sh->sequence_header_code = MPEG2_START_SEQUENCE_HEADER; + + sh->horizontal_size_value = avctx->width & 0xfff; + sh->vertical_size_value = avctx->height & 0xfff; + + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + AVRational dar = av_div_q(avctx->sample_aspect_ratio, + (AVRational) { avctx->width, avctx->height }); + + if (av_cmp_q(avctx->sample_aspect_ratio, (AVRational) { 1, 1 }) == 0) { + sh->aspect_ratio_information = 1; + } else if (av_cmp_q(dar, (AVRational) { 3, 4 }) == 0) { + sh->aspect_ratio_information = 2; + } else if (av_cmp_q(dar, (AVRational) { 9, 16 }) == 0) { + sh->aspect_ratio_information = 3; + } else if (av_cmp_q(dar, (AVRational) { 100, 221 }) == 0) { + sh->aspect_ratio_information = 4; + } else { + av_log(avctx, AV_LOG_WARNING, "Sample aspect ratio %d:%d is not " + "representable, signalling square pixels instead.\n", + avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den); + sh->aspect_ratio_information = 1; + } + } else { + // Unknown - assume square pixels. + sh->aspect_ratio_information = 1; + } + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) - vseq->frame_rate = (float)avctx->framerate.num / avctx->framerate.den; + priv->frame_rate = avctx->framerate; else - vseq->frame_rate = (float)avctx->time_base.den / avctx->time_base.num; + priv->frame_rate = av_inv_q(avctx->time_base); + ff_mpeg12_find_best_frame_rate(priv->frame_rate, + &code, &ext_n, &ext_d, 0); + sh->frame_rate_code = code; - vseq->aspect_ratio_information = 1; - vseq->vbv_buffer_size = avctx->rc_buffer_size / (16 * 1024); + sh->bit_rate_value = priv->bit_rate & 0x3ffff; + sh->vbv_buffer_size_value = priv->vbv_buffer_size & 0x3ff; - vseq->sequence_extension.bits.profile_and_level_indication = - avctx->profile << 4 | avctx->level; - vseq->sequence_extension.bits.progressive_sequence = 1; - vseq->sequence_extension.bits.chroma_format = 1; - vseq->sequence_extension.bits.low_delay = 0; - vseq->sequence_extension.bits.frame_rate_extension_n = 0; - vseq->sequence_extension.bits.frame_rate_extension_d = 0; + sh->constrained_parameters_flag = 0; + sh->load_intra_quantiser_matrix = 0; + sh->load_non_intra_quantiser_matrix = 0; - vseq->new_gop_header = 0; - vseq->gop_header.bits.time_code = 0; - vseq->gop_header.bits.closed_gop = 1; - vseq->gop_header.bits.broken_link = 0; - vpic->forward_reference_picture = VA_INVALID_ID; - vpic->backward_reference_picture = VA_INVALID_ID; - vpic->reconstructed_picture = VA_INVALID_ID; + // Sequence extension - vpic->coded_buf = VA_INVALID_ID; + priv->sequence_extension.extension_start_code = MPEG2_START_EXTENSION; + priv->sequence_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE; - vpic->temporal_reference = 0; - vpic->f_code[0][0] = 15; - vpic->f_code[0][1] = 15; - vpic->f_code[1][0] = 15; - vpic->f_code[1][1] = 15; + se->profile_and_level_indication = avctx->profile << 4 | avctx->level; + se->progressive_sequence = 1; + se->chroma_format = 1; - vpic->picture_coding_extension.bits.intra_dc_precision = 0; - vpic->picture_coding_extension.bits.picture_structure = 3; - vpic->picture_coding_extension.bits.top_field_first = 0; - vpic->picture_coding_extension.bits.frame_pred_frame_dct = 1; - vpic->picture_coding_extension.bits.concealment_motion_vectors = 0; - vpic->picture_coding_extension.bits.q_scale_type = 0; - vpic->picture_coding_extension.bits.intra_vlc_format = 0; - vpic->picture_coding_extension.bits.alternate_scan = 0; - vpic->picture_coding_extension.bits.repeat_first_field = 0; - vpic->picture_coding_extension.bits.progressive_frame = 1; - vpic->picture_coding_extension.bits.composite_display_flag = 0; + se->horizontal_size_extension = avctx->width >> 12; + se->vertical_size_extension = avctx->height >> 12; - priv->bit_rate = (avctx->bit_rate + 399) / 400; - priv->vbv_buffer_size = avctx->rc_buffer_size / (16 * 1024); + se->bit_rate_extension = priv->bit_rate >> 18; + se->vbv_buffer_size_extension = priv->vbv_buffer_size >> 10; + se->low_delay = ctx->b_per_p == 0; + + se->frame_rate_extension_n = ext_n; + se->frame_rate_extension_d = ext_d; + + + // Sequence display extension + + priv->sequence_display_extension.extension_start_code = + MPEG2_START_EXTENSION; + priv->sequence_display_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE_DISPLAY; + + sde->video_format = 5; + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + sde->colour_description = 1; + sde->colour_primaries = avctx->color_primaries; + sde->transfer_characteristics = avctx->color_trc; + sde->matrix_coefficients = avctx->colorspace; + } else { + sde->colour_description = 0; + } + + sde->display_horizontal_size = avctx->width; + sde->display_vertical_size = avctx->height; + + + // GOP header + + goph->group_start_code = MPEG2_START_GROUP; + + goph->time_code = 0; + goph->closed_gop = 1; + goph->broken_link = 0; + + + // Defaults for picture header + + ph->picture_start_code = MPEG2_START_PICTURE; + + ph->vbv_delay = 0xffff; // Not currently calculated. + + ph->full_pel_forward_vector = 0; + ph->forward_f_code = 7; + ph->full_pel_backward_vector = 0; + ph->forward_f_code = 7; + + + // Defaults for picture coding extension + + priv->picture_coding_extension.extension_start_code = + MPEG2_START_EXTENSION; + priv->picture_coding_extension.extension_start_code_identifier = + MPEG2_EXTENSION_PICTURE_CODING; + + pce->intra_dc_precision = 0; + pce->picture_structure = 3; + pce->top_field_first = 0; + pce->frame_pred_frame_dct = 1; + pce->concealment_motion_vectors = 0; + pce->q_scale_type = 0; + pce->intra_vlc_format = 0; + pce->alternate_scan = 0; + pce->repeat_first_field = 0; + pce->progressive_frame = 1; + pce->composite_display_flag = 0; + + + + *vseq = (VAEncSequenceParameterBufferMPEG2) { + .intra_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + + .picture_width = avctx->width, + .picture_height = avctx->height, + + .bits_per_second = avctx->bit_rate, + .frame_rate = av_q2d(priv->frame_rate), + .aspect_ratio_information = sh->aspect_ratio_information, + .vbv_buffer_size = priv->vbv_buffer_size, + + .sequence_extension.bits = { + .profile_and_level_indication = se->profile_and_level_indication, + .progressive_sequence = se->progressive_sequence, + .chroma_format = se->chroma_format, + .low_delay = se->low_delay, + .frame_rate_extension_n = se->frame_rate_extension_n, + .frame_rate_extension_d = se->frame_rate_extension_d, + }, + + .new_gop_header = 1, + .gop_header.bits = { + .time_code = goph->time_code, + .closed_gop = goph->closed_gop, + .broken_link = goph->broken_link, + }, + }; + + *vpic = (VAEncPictureParameterBufferMPEG2) { + .forward_reference_picture = VA_INVALID_ID, + .backward_reference_picture = VA_INVALID_ID, + .reconstructed_picture = VA_INVALID_ID, + .coded_buf = VA_INVALID_ID, + + .vbv_delay = 0xffff, + .f_code = { { 15, 15 }, { 15, 15 } }, + + .picture_coding_extension.bits = { + .intra_dc_precision = pce->intra_dc_precision, + .picture_structure = pce->picture_structure, + .top_field_first = pce->top_field_first, + .frame_pred_frame_dct = pce->frame_pred_frame_dct, + .concealment_motion_vectors = pce->concealment_motion_vectors, + .q_scale_type = pce->q_scale_type, + .intra_vlc_format = pce->intra_vlc_format, + .alternate_scan = pce->alternate_scan, + .repeat_first_field = pce->repeat_first_field, + .progressive_frame = pce->progressive_frame, + .composite_display_flag = pce->composite_display_flag, + }, + + .composite_display.bits = { + .v_axis = pce->v_axis, + .field_sequence = pce->field_sequence, + .sub_carrier = pce->sub_carrier, + .burst_amplitude = pce->burst_amplitude, + .sub_carrier_phase = pce->sub_carrier_phase, + }, + }; return 0; } @@ -260,56 +417,61 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; VAAPIEncodeMPEG2Context *priv = ctx->priv_data; - int fch, fcv; + MPEG2RawPictureHeader *ph = &priv->picture_header; + MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; + VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; - switch (avctx->level) { - case 4: // High. - case 6: // High 1440. - fch = 9; - fcv = 5; - break; - case 8: // Main. - fch = 8; - fcv = 5; - break; - case 10: // Low. - default: - fch = 7; - fcv = 4; - break; + if (pic->type == PICTURE_TYPE_IDR || pic->type == PICTURE_TYPE_I) { + ph->temporal_reference = 0; + ph->picture_coding_type = 1; + priv->last_i_frame = pic->display_order; + } else { + ph->temporal_reference = pic->display_order - priv->last_i_frame; + ph->picture_coding_type = pic->type == PICTURE_TYPE_B ? 3 : 2; } + if (pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B) { + pce->f_code[0][0] = priv->f_code_horizontal; + pce->f_code[0][1] = priv->f_code_vertical; + } else { + pce->f_code[0][0] = 15; + pce->f_code[0][1] = 15; + } + if (pic->type == PICTURE_TYPE_B) { + pce->f_code[1][0] = priv->f_code_horizontal; + pce->f_code[1][1] = priv->f_code_vertical; + } else { + pce->f_code[1][0] = 15; + pce->f_code[1][1] = 15; + } + + vpic->reconstructed_picture = pic->recon_surface; + vpic->coded_buf = pic->output_buffer; + switch (pic->type) { case PICTURE_TYPE_IDR: case PICTURE_TYPE_I: vpic->picture_type = VAEncPictureTypeIntra; - priv->last_i_frame = pic->display_order; break; case PICTURE_TYPE_P: vpic->picture_type = VAEncPictureTypePredictive; vpic->forward_reference_picture = pic->refs[0]->recon_surface; - vpic->f_code[0][0] = fch; - vpic->f_code[0][1] = fcv; break; case PICTURE_TYPE_B: vpic->picture_type = VAEncPictureTypeBidirectional; vpic->forward_reference_picture = pic->refs[0]->recon_surface; vpic->backward_reference_picture = pic->refs[1]->recon_surface; - vpic->f_code[0][0] = fch; - vpic->f_code[0][1] = fcv; - vpic->f_code[1][0] = fch; - vpic->f_code[1][1] = fcv; break; default: av_assert0(0 && "invalid picture type"); } - vpic->reconstructed_picture = pic->recon_surface; - vpic->coded_buf = pic->output_buffer; - - vpic->temporal_reference = pic->display_order - priv->last_i_frame; + vpic->temporal_reference = ph->temporal_reference; + vpic->f_code[0][0] = pce->f_code[0][0]; + vpic->f_code[0][1] = pce->f_code[0][1]; + vpic->f_code[1][0] = pce->f_code[1][0]; + vpic->f_code[1][1] = pce->f_code[1][1]; pic->nb_slices = priv->mb_height; @@ -354,6 +516,11 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_MPEG2VIDEO, avctx); + if (err < 0) + return err; priv->mb_width = FFALIGN(avctx->width, 16) / 16; priv->mb_height = FFALIGN(avctx->height, 16) / 16; @@ -420,11 +587,41 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) case FF_PROFILE_MPEG2_MAIN: ctx->va_profile = VAProfileMPEG2Main; break; + case FF_PROFILE_MPEG2_422: + av_log(avctx, AV_LOG_ERROR, "MPEG-2 4:2:2 profile " + "is not supported.\n"); + return AVERROR_PATCHWELCOME; + case FF_PROFILE_MPEG2_HIGH: + av_log(avctx, AV_LOG_ERROR, "MPEG-2 high profile " + "is not supported.\n"); + return AVERROR_PATCHWELCOME; + case FF_PROFILE_MPEG2_SS: + case FF_PROFILE_MPEG2_SNR_SCALABLE: + av_log(avctx, AV_LOG_ERROR, "MPEG-2 scalable profiles " + "are not supported.\n"); + return AVERROR_PATCHWELCOME; default: av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n", avctx->profile); return AVERROR(EINVAL); } + switch (avctx->level) { + case 4: // High + case 6: // High 1440 + case 8: // Main + case 10: // Low + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 level %d.\n", + avctx->level); + return AVERROR(EINVAL); + } + + if (avctx->height % 4096 == 0 || avctx->width % 4096 == 0) { + av_log(avctx, AV_LOG_ERROR, "MPEG-2 does not support picture " + "height or width divisible by 4096.\n"); + return AVERROR(EINVAL); + } ctx->va_entrypoint = VAEntrypointEncSlice; ctx->va_rt_format = VA_RT_FORMAT_YUV420; @@ -439,6 +636,17 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + + if (priv) + ff_cbs_close(&priv->cbc); + + return ff_vaapi_encode_close(avctx); +} + static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = { { "profile", "4" }, { "level", "4" }, @@ -460,11 +668,12 @@ AVCodec ff_mpeg2_vaapi_encoder = { .priv_data_size = sizeof(VAAPIEncodeContext), .init = &vaapi_encode_mpeg2_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, - .capabilities = AV_CODEC_CAP_DELAY, + .close = &vaapi_encode_mpeg2_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_mpeg2_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c index 423f7483e..b4c5521d1 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -260,10 +260,11 @@ AVCodec ff_vp8_vaapi_encoder = { .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_vp8_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_vp8_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c index a987d1cd7..9108699ac 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -304,10 +304,11 @@ AVCodec ff_vp9_vaapi_encoder = { .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_vp9_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_vp9_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 30e7026cc..5854587a2 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -388,7 +388,7 @@ static int vaapi_h264_decode_slice(AVCodecContext *avctx, return 0; } -AVHWAccel ff_h264_vaapi_hwaccel = { +const AVHWAccel ff_h264_vaapi_hwaccel = { .name = "h264_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -399,6 +399,7 @@ AVHWAccel ff_h264_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 69b8e478c..19aabcdb5 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -423,7 +423,7 @@ static int vaapi_hevc_decode_slice(AVCodecContext *avctx, return 0; } -AVHWAccel ff_hevc_vaapi_hwaccel = { +const AVHWAccel ff_hevc_vaapi_hwaccel = { .name = "hevc_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -434,6 +434,7 @@ AVHWAccel ff_hevc_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePictureHEVC), .init = ff_vaapi_decode_init, .uninit = ff_vaapi_decode_uninit, + .frame_params = ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c index 0d197c969..aaed434c8 100644 --- a/libavcodec/vaapi_mpeg2.c +++ b/libavcodec/vaapi_mpeg2.c @@ -172,7 +172,7 @@ static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer return 0; } -AVHWAccel ff_mpeg2_vaapi_hwaccel = { +const AVHWAccel ff_mpeg2_vaapi_hwaccel = { .name = "mpeg2_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -183,6 +183,7 @@ AVHWAccel ff_mpeg2_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c index f8c5ddf20..11860ff74 100644 --- a/libavcodec/vaapi_mpeg4.c +++ b/libavcodec/vaapi_mpeg4.c @@ -178,7 +178,7 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer } #if CONFIG_MPEG4_VAAPI_HWACCEL -AVHWAccel ff_mpeg4_vaapi_hwaccel = { +const AVHWAccel ff_mpeg4_vaapi_hwaccel = { .name = "mpeg4_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG4, @@ -189,13 +189,14 @@ AVHWAccel ff_mpeg4_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; #endif #if CONFIG_H263_VAAPI_HWACCEL -AVHWAccel ff_h263_vaapi_hwaccel = { +const AVHWAccel ff_h263_vaapi_hwaccel = { .name = "h263_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H263, @@ -206,6 +207,7 @@ AVHWAccel ff_h263_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c index 30c9ed3c8..525376790 100644 --- a/libavcodec/vaapi_vc1.c +++ b/libavcodec/vaapi_vc1.c @@ -388,7 +388,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, } #if CONFIG_WMV3_VAAPI_HWACCEL -AVHWAccel ff_wmv3_vaapi_hwaccel = { +const AVHWAccel ff_wmv3_vaapi_hwaccel = { .name = "wmv3_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -399,12 +399,13 @@ AVHWAccel ff_wmv3_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; #endif -AVHWAccel ff_vc1_vaapi_hwaccel = { +const AVHWAccel ff_vc1_vaapi_hwaccel = { .name = "vc1_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -415,6 +416,7 @@ AVHWAccel ff_vc1_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c new file mode 100644 index 000000000..2426b30f1 --- /dev/null +++ b/libavcodec/vaapi_vp8.c @@ -0,0 +1,237 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "hwaccel.h" +#include "vaapi_decode.h" +#include "vp8.h" + +static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf) +{ + if (vf) + return ff_vaapi_get_surface_id(vf->tf.f); + else + return VA_INVALID_SURFACE; +} + +static int vaapi_vp8_start_frame(AVCodecContext *avctx, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + const VP8Context *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private; + VAPictureParameterBufferVP8 pp; + VAProbabilityDataBufferVP8 prob; + VAIQMatrixBufferVP8 quant; + int err, i, j, k; + + pic->output_surface = vaapi_vp8_surface_id(s->framep[VP56_FRAME_CURRENT]); + + pp = (VAPictureParameterBufferVP8) { + .frame_width = avctx->width, + .frame_height = avctx->height, + + .last_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_PREVIOUS]), + .golden_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN]), + .alt_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN2]), + .out_of_loop_frame = VA_INVALID_SURFACE, + + .pic_fields.bits = { + .key_frame = !s->keyframe, + .version = s->profile, + + .segmentation_enabled = s->segmentation.enabled, + .update_mb_segmentation_map = s->segmentation.update_map, + .update_segment_feature_data = s->segmentation.update_feature_data, + + .filter_type = s->filter.simple, + .sharpness_level = s->filter.sharpness, + + .loop_filter_adj_enable = s->lf_delta.enabled, + .mode_ref_lf_delta_update = s->lf_delta.update, + + .sign_bias_golden = s->sign_bias[VP56_FRAME_GOLDEN], + .sign_bias_alternate = s->sign_bias[VP56_FRAME_GOLDEN2], + + .mb_no_coeff_skip = s->mbskip_enabled, + .loop_filter_disable = s->filter.level == 0, + }, + + .prob_skip_false = s->prob->mbskip, + .prob_intra = s->prob->intra, + .prob_last = s->prob->last, + .prob_gf = s->prob->golden, + }; + + for (i = 0; i < 3; i++) + pp.mb_segment_tree_probs[i] = s->prob->segmentid[i]; + + for (i = 0; i < 4; i++) { + if (s->segmentation.enabled) { + pp.loop_filter_level[i] = s->segmentation.filter_level[i]; + if (!s->segmentation.absolute_vals) + pp.loop_filter_level[i] += s->filter.level; + } else { + pp.loop_filter_level[i] = s->filter.level; + } + pp.loop_filter_level[i] = av_clip_uintp2(pp.loop_filter_level[i], 6); + } + + for (i = 0; i < 4; i++) { + pp.loop_filter_deltas_ref_frame[i] = s->lf_delta.ref[i]; + pp.loop_filter_deltas_mode[i] = s->lf_delta.mode[i + 4]; + } + + if (s->keyframe) { + static const uint8_t keyframe_y_mode_probs[4] = { + 145, 156, 163, 128 + }; + static const uint8_t keyframe_uv_mode_probs[3] = { + 142, 114, 183 + }; + memcpy(pp.y_mode_probs, keyframe_y_mode_probs, 4); + memcpy(pp.uv_mode_probs, keyframe_uv_mode_probs, 3); + } else { + for (i = 0; i < 4; i++) + pp.y_mode_probs[i] = s->prob->pred16x16[i]; + for (i = 0; i < 3; i++) + pp.uv_mode_probs[i] = s->prob->pred8x8c[i]; + } + for (i = 0; i < 2; i++) + for (j = 0; j < 19; j++) + pp.mv_probs[i][j] = s->prob->mvc[i][j]; + + pp.bool_coder_ctx.range = s->coder_state_at_header_end.range; + pp.bool_coder_ctx.value = s->coder_state_at_header_end.value; + pp.bool_coder_ctx.count = s->coder_state_at_header_end.bit_count; + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAPictureParameterBufferType, + &pp, sizeof(pp)); + if (err < 0) + goto fail; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 8; j++) { + static const int coeff_bands_inverse[8] = { + 0, 1, 2, 3, 5, 6, 4, 15 + }; + int coeff_pos = coeff_bands_inverse[j]; + + for (k = 0; k < 3; k++) { + memcpy(prob.dct_coeff_probs[i][j][k], + s->prob->token[i][coeff_pos][k], 11); + } + } + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAProbabilityBufferType, + &prob, sizeof(prob)); + if (err < 0) + goto fail; + + for (i = 0; i < 4; i++) { + int base_qi = s->segmentation.base_quant[i]; + if (!s->segmentation.absolute_vals) + base_qi += s->quant.yac_qi; + + quant.quantization_index[i][0] = av_clip_uintp2(base_qi, 7); + quant.quantization_index[i][1] = av_clip_uintp2(base_qi + s->quant.ydc_delta, 7); + quant.quantization_index[i][2] = av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7); + quant.quantization_index[i][3] = av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7); + quant.quantization_index[i][4] = av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7); + quant.quantization_index[i][5] = av_clip_uintp2(base_qi + s->quant.uvac_delta, 7); + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAIQMatrixBufferType, + &quant, sizeof(quant)); + if (err < 0) + goto fail; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; +} + +static int vaapi_vp8_end_frame(AVCodecContext *avctx) +{ + const VP8Context *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private; + + return ff_vaapi_decode_issue(avctx, pic); +} + +static int vaapi_vp8_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + const VP8Context *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private; + VASliceParameterBufferVP8 sp; + int err, i; + + unsigned int header_size = 3 + 7 * s->keyframe; + const uint8_t *data = buffer + header_size; + unsigned int data_size = size - header_size; + + sp = (VASliceParameterBufferVP8) { + .slice_data_size = data_size, + .slice_data_offset = 0, + .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, + + .macroblock_offset = (8 * (s->coder_state_at_header_end.input - data) - + s->coder_state_at_header_end.bit_count - 8), + .num_of_partitions = s->num_coeff_partitions + 1, + }; + + sp.partition_size[0] = s->header_partition_size - ((sp.macroblock_offset + 7) / 8); + for (i = 0; i < 8; i++) + sp.partition_size[i+1] = s->coeff_partition_size[i]; + + err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), data, data_size); + if (err) + goto fail; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; +} + +const AVHWAccel ff_vp8_vaapi_hwaccel = { + .name = "vp8_vaapi", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP8, + .pix_fmt = AV_PIX_FMT_VAAPI, + .start_frame = &vaapi_vp8_start_frame, + .end_frame = &vaapi_vp8_end_frame, + .decode_slice = &vaapi_vp8_decode_slice, + .frame_priv_data_size = sizeof(VAAPIDecodePicture), + .init = &ff_vaapi_decode_init, + .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, + .priv_data_size = sizeof(VAAPIDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c index d8ece75df..f384ba787 100644 --- a/libavcodec/vaapi_vp9.c +++ b/libavcodec/vaapi_vp9.c @@ -168,7 +168,7 @@ static int vaapi_vp9_decode_slice(AVCodecContext *avctx, return 0; } -AVHWAccel ff_vp9_vaapi_hwaccel = { +const AVHWAccel ff_vp9_vaapi_hwaccel = { .name = "vp9_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -179,6 +179,7 @@ AVHWAccel ff_vp9_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = ff_vaapi_decode_init, .uninit = ff_vaapi_decode_uninit, + .frame_params = ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 16c601e75..cbef89f25 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -29,6 +29,7 @@ #include "avcodec.h" #include "blockdsp.h" #include "get_bits.h" +#include "hwaccel.h" #include "internal.h" #include "mpeg_er.h" #include "mpegvideo.h" @@ -37,7 +38,6 @@ #include "profiles.h" #include "vc1.h" #include "vc1data.h" -#include "vdpau_compat.h" #include "libavutil/avassert.h" @@ -657,15 +657,6 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, return buf_size; } -#if FF_API_CAP_VDPAU - if (s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) { - if (v->profile < PROFILE_ADVANCED) - avctx->pix_fmt = AV_PIX_FMT_VDPAU_WMV3; - else - avctx->pix_fmt = AV_PIX_FMT_VDPAU_VC1; - } -#endif - //for advanced profile we may need to parse and unescape data if (avctx->codec_id == AV_CODEC_ID_VC1 || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) { int buf_size2 = 0; @@ -684,21 +675,13 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, if (size <= 0) continue; switch (AV_RB32(start)) { case VC1_CODE_FRAME: - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) buf_start = start; buf_size2 = vc1_unescape_buffer(start + 4, size, buf2); break; case VC1_CODE_FIELD: { int buf_size3; - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) buf_start_second_field = start; tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1)); if (!tmp) { @@ -764,11 +747,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, ret = AVERROR_INVALIDDATA; goto err; } else { // found field marker, unescape second field - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) buf_start_second_field = divider; tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1)); if (!tmp) { @@ -917,17 +896,6 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, s->me.qpel_put = s->qdsp.put_qpel_pixels_tab; s->me.qpel_avg = s->qdsp.avg_qpel_pixels_tab; -#if FF_API_CAP_VDPAU - if ((CONFIG_VC1_VDPAU_DECODER) - &&s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) { - if (v->field_mode && buf_start_second_field) { - ff_vdpau_vc1_decode_picture(s, buf_start, buf_start_second_field - buf_start); - ff_vdpau_vc1_decode_picture(s, buf_start_second_field, (buf + buf_size) - buf_start_second_field); - } else { - ff_vdpau_vc1_decode_picture(s, buf_start, (buf + buf_size) - buf_start); - } - } else -#endif if (avctx->hwaccel) { s->mb_y = 0; if (v->field_mode && buf_start_second_field) { @@ -1152,6 +1120,9 @@ static const enum AVPixelFormat vc1_hwaccel_pixfmt_list_420[] = { AV_PIX_FMT_D3D11VA_VLD, AV_PIX_FMT_D3D11, #endif +#if CONFIG_VC1_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_VC1_VAAPI_HWACCEL AV_PIX_FMT_VAAPI, #endif @@ -1174,6 +1145,27 @@ AVCodec ff_vc1_decoder = { .flush = ff_mpeg_flush, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .pix_fmts = vc1_hwaccel_pixfmt_list_420, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_VC1_DXVA2_HWACCEL + HWACCEL_DXVA2(vc1), +#endif +#if CONFIG_VC1_D3D11VA_HWACCEL + HWACCEL_D3D11VA(vc1), +#endif +#if CONFIG_VC1_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(vc1), +#endif +#if CONFIG_VC1_NVDEC_HWACCEL + HWACCEL_NVDEC(vc1), +#endif +#if CONFIG_VC1_VAAPI_HWACCEL + HWACCEL_VAAPI(vc1), +#endif +#if CONFIG_VC1_VDPAU_HWACCEL + HWACCEL_VDPAU(vc1), +#endif + NULL + }, .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) }; @@ -1190,38 +1182,27 @@ AVCodec ff_wmv3_decoder = { .flush = ff_mpeg_flush, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .pix_fmts = vc1_hwaccel_pixfmt_list_420, - .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) -}; + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_WMV3_DXVA2_HWACCEL + HWACCEL_DXVA2(wmv3), #endif - -#if CONFIG_WMV3_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_wmv3_vdpau_decoder = { - .name = "wmv3_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 VDPAU"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_WMV3, - .priv_data_size = sizeof(VC1Context), - .init = vc1_decode_init, - .close = ff_vc1_decode_end, - .decode = vc1_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HWACCEL_VDPAU, - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_WMV3, AV_PIX_FMT_NONE }, - .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) -}; +#if CONFIG_WMV3_D3D11VA_HWACCEL + HWACCEL_D3D11VA(wmv3), #endif - -#if CONFIG_VC1_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_vc1_vdpau_decoder = { - .name = "vc1_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1 VDPAU"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VC1, - .priv_data_size = sizeof(VC1Context), - .init = vc1_decode_init, - .close = ff_vc1_decode_end, - .decode = vc1_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HWACCEL_VDPAU, - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_VC1, AV_PIX_FMT_NONE }, +#if CONFIG_WMV3_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(wmv3), +#endif +#if CONFIG_WMV3_NVDEC_HWACCEL + HWACCEL_NVDEC(wmv3), +#endif +#if CONFIG_WMV3_VAAPI_HWACCEL + HWACCEL_VAAPI(wmv3), +#endif +#if CONFIG_WMV3_VDPAU_HWACCEL + HWACCEL_VDPAU(wmv3), +#endif + NULL + }, .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) }; #endif diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c index 96e27d93e..2f08441d5 100644 --- a/libavcodec/vc2enc.c +++ b/libavcodec/vc2enc.c @@ -1063,7 +1063,7 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) { Plane *p; SubBand *b; - int i, j, level, o, shift; + int i, j, level, o, shift, ret; const AVPixFmtDescriptor *fmt = av_pix_fmt_desc_get(avctx->pix_fmt); const int depth = fmt->comp[0].depth; VC2EncContext *s = avctx->priv_data; @@ -1138,7 +1138,9 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) } /* Chroma subsampling */ - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + if (ret) + return ret; /* Bit depth and color range index */ if (depth == 8 && avctx->color_range == AVCOL_RANGE_JPEG) { @@ -1171,7 +1173,7 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) p->dwt_width = w = FFALIGN(p->width, (1 << s->wavelet_depth)); p->dwt_height = h = FFALIGN(p->height, (1 << s->wavelet_depth)); p->coef_stride = FFALIGN(p->dwt_width, 32); - p->coef_buf = av_malloc(p->coef_stride*p->dwt_height*sizeof(dwtcoef)); + p->coef_buf = av_mallocz(p->coef_stride*p->dwt_height*sizeof(dwtcoef)); if (!p->coef_buf) goto alloc_fail; for (level = s->wavelet_depth-1; level >= 0; level--) { @@ -1190,7 +1192,8 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) /* DWT init */ if (ff_vc2enc_init_transforms(&s->transform_args[i].t, s->plane[i].coef_stride, - s->plane[i].dwt_height)) + s->plane[i].dwt_height, + s->slice_width, s->slice_height)) goto alloc_fail; } diff --git a/libavcodec/vc2enc_dwt.c b/libavcodec/vc2enc_dwt.c index c60b003a3..d22af8a31 100644 --- a/libavcodec/vc2enc_dwt.c +++ b/libavcodec/vc2enc_dwt.c @@ -255,21 +255,27 @@ static void vc2_subband_dwt_haar_shift(VC2TransformContext *t, dwtcoef *data, dwt_haar(t, data, stride, width, height, 1); } -av_cold int ff_vc2enc_init_transforms(VC2TransformContext *s, int p_width, int p_height) +av_cold int ff_vc2enc_init_transforms(VC2TransformContext *s, int p_stride, + int p_height, int slice_w, int slice_h) { s->vc2_subband_dwt[VC2_TRANSFORM_9_7] = vc2_subband_dwt_97; s->vc2_subband_dwt[VC2_TRANSFORM_5_3] = vc2_subband_dwt_53; s->vc2_subband_dwt[VC2_TRANSFORM_HAAR] = vc2_subband_dwt_haar; s->vc2_subband_dwt[VC2_TRANSFORM_HAAR_S] = vc2_subband_dwt_haar_shift; - s->buffer = av_malloc(2*p_width*p_height*sizeof(dwtcoef)); + /* Pad by the slice size, only matters for non-Haar wavelets */ + s->buffer = av_calloc((p_stride + slice_w)*(p_height + slice_h), sizeof(dwtcoef)); if (!s->buffer) return 1; + s->padding = (slice_h >> 1)*p_stride + (slice_w >> 1); + s->buffer += s->padding; + return 0; } av_cold void ff_vc2enc_free_transforms(VC2TransformContext *s) { - av_freep(&s->buffer); + av_free(s->buffer - s->padding); + s->buffer = NULL; } diff --git a/libavcodec/vc2enc_dwt.h b/libavcodec/vc2enc_dwt.h index 7fbbfbe0e..a6932bcda 100644 --- a/libavcodec/vc2enc_dwt.h +++ b/libavcodec/vc2enc_dwt.h @@ -41,12 +41,14 @@ enum VC2TransformType { typedef struct VC2TransformContext { dwtcoef *buffer; + int padding; void (*vc2_subband_dwt[VC2_TRANSFORMS_NB])(struct VC2TransformContext *t, dwtcoef *data, ptrdiff_t stride, int width, int height); } VC2TransformContext; -int ff_vc2enc_init_transforms(VC2TransformContext *t, int p_width, int p_height); +int ff_vc2enc_init_transforms(VC2TransformContext *t, int p_stride, int p_height, + int slice_w, int slice_h); void ff_vc2enc_free_transforms(VC2TransformContext *t); #endif /* AVCODEC_VC2ENC_DWT_H */ diff --git a/libavcodec/vda.c b/libavcodec/vda.c deleted file mode 100644 index 819ae030b..000000000 --- a/libavcodec/vda.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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/mem.h" - -#include "vda.h" -#include "vda_vt_internal.h" - -#if CONFIG_H264_VDA_HWACCEL -AVVDAContext *av_vda_alloc_context(void) -{ - AVVDAContext *ret = av_mallocz(sizeof(*ret)); - - if (ret) { - ret->output_callback = ff_vda_output_callback; - ret->cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8; - } - - return ret; -} - -int av_vda_default_init(AVCodecContext *avctx) -{ - return av_vda_default_init2(avctx, NULL); -} - -int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx) -{ - avctx->hwaccel_context = vdactx ?: av_vda_alloc_context(); - if (!avctx->hwaccel_context) - return AVERROR(ENOMEM); - return ff_vda_default_init(avctx); -} - -void av_vda_default_free(AVCodecContext *avctx) -{ - ff_vda_default_free(avctx); - av_freep(&avctx->hwaccel_context); -} - -void ff_vda_default_free(AVCodecContext *avctx) -{ - AVVDAContext *vda = avctx->hwaccel_context; - if (vda && vda->decoder) - VDADecoderDestroy(vda->decoder); -} - -#else -AVVDAContext *av_vda_alloc_context(void) -{ - return NULL; -} - -int av_vda_default_init(AVCodecContext *avctx) -{ - return AVERROR(ENOSYS); -} - -int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx) -{ - return AVERROR(ENOSYS); -} - -void av_vda_default_free(AVCodecContext *ctx) -{ -} -#endif diff --git a/libavcodec/vda.h b/libavcodec/vda.h deleted file mode 100644 index bde14e31d..000000000 --- a/libavcodec/vda.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * VDA HW acceleration - * - * copyright (c) 2011 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_VDA_H -#define AVCODEC_VDA_H - -/** - * @file - * @ingroup lavc_codec_hwaccel_vda - * Public libavcodec VDA header. - */ - -#include "libavcodec/avcodec.h" - -#include - -// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes -// http://openradar.appspot.com/8026390 -#undef __GNUC_STDC_INLINE__ - -#define Picture QuickdrawPicture -#include -#undef Picture - -#include "libavcodec/version.h" - -// extra flags not defined in VDADecoder.h -enum { - kVDADecodeInfo_Asynchronous = 1UL << 0, - kVDADecodeInfo_FrameDropped = 1UL << 1 -}; - -/** - * @defgroup lavc_codec_hwaccel_vda VDA - * @ingroup lavc_codec_hwaccel - * - * @{ - */ - -/** - * This structure is used to provide the necessary configurations and data - * to the VDA FFmpeg HWAccel implementation. - * - * The application must make it available as AVCodecContext.hwaccel_context. - */ -struct vda_context { - /** - * VDA decoder object. - * - * - encoding: unused - * - decoding: Set/Unset by libavcodec. - */ - VDADecoder decoder; - - /** - * The Core Video pixel buffer that contains the current image data. - * - * encoding: unused - * decoding: Set by libavcodec. Unset by user. - */ - CVPixelBufferRef cv_buffer; - - /** - * Use the hardware decoder in synchronous mode. - * - * encoding: unused - * decoding: Set by user. - */ - int use_sync_decoding; - - /** - * The frame width. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - int width; - - /** - * The frame height. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - int height; - - /** - * The frame format. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - int format; - - /** - * The pixel format for output image buffers. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - OSType cv_pix_fmt_type; - - /** - * unused - */ - uint8_t *priv_bitstream; - - /** - * unused - */ - int priv_bitstream_size; - - /** - * unused - */ - int priv_allocated_size; - - /** - * Use av_buffer to manage buffer. - * When the flag is set, the CVPixelBuffers returned by the decoder will - * be released automatically, so you have to retain them if necessary. - * Not setting this flag may cause memory leak. - * - * encoding: unused - * decoding: Set by user. - */ - int use_ref_buffer; -}; - -/** Create the video decoder. */ -int ff_vda_create_decoder(struct vda_context *vda_ctx, - uint8_t *extradata, - int extradata_size); - -/** Destroy the video decoder. */ -int ff_vda_destroy_decoder(struct vda_context *vda_ctx); - -/** - * This struct holds all the information that needs to be passed - * between the caller and libavcodec for initializing VDA decoding. - * Its size is not a part of the public ABI, it must be allocated with - * av_vda_alloc_context() and freed with av_free(). - */ -typedef struct AVVDAContext { - /** - * VDA decoder object. Created and freed by the caller. - */ - VDADecoder decoder; - - /** - * The output callback that must be passed to VDADecoderCreate. - * Set by av_vda_alloc_context(). - */ - VDADecoderOutputCallback output_callback; - - /** - * CVPixelBuffer Format Type that VDA will use for decoded frames; set by - * the caller. - */ - OSType cv_pix_fmt_type; -} AVVDAContext; - -/** - * Allocate and initialize a VDA context. - * - * This function should be called from the get_format() callback when the caller - * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder - * object (using the output callback provided by libavcodec) that will be used - * for VDA-accelerated decoding. - * - * When decoding with VDA is finished, the caller must destroy the decoder - * object and free the VDA context using av_free(). - * - * @return the newly allocated context or NULL on failure - */ -AVVDAContext *av_vda_alloc_context(void); - -/** - * This is a convenience function that creates and sets up the VDA context using - * an internal implementation. - * - * @param avctx the corresponding codec context - * - * @return >= 0 on success, a negative AVERROR code on failure - */ -int av_vda_default_init(AVCodecContext *avctx); - -/** - * This is a convenience function that creates and sets up the VDA context using - * an internal implementation. - * - * @param avctx the corresponding codec context - * @param vdactx the VDA context to use - * - * @return >= 0 on success, a negative AVERROR code on failure - */ -int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx); - -/** - * This function must be called to free the VDA context initialized with - * av_vda_default_init(). - * - * @param avctx the corresponding codec context - */ -void av_vda_default_free(AVCodecContext *avctx); - -/** - * @} - */ - -#endif /* AVCODEC_VDA_H */ diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c deleted file mode 100644 index 7b88ec701..000000000 --- a/libavcodec/vda_h264.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * VDA H264 HW acceleration. - * - * copyright (c) 2011 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 - */ - -#include -#include -#include - -#include "vda.h" -#include "libavutil/avutil.h" -#include "h264dec.h" - -struct vda_buffer { - CVPixelBufferRef cv_buffer; -}; -#include "internal.h" -#include "vda_vt_internal.h" - -/* Decoder callback that adds the vda frame to the queue in display order. */ -static void vda_decoder_callback(void *vda_hw_ctx, - CFDictionaryRef user_info, - OSStatus status, - uint32_t infoFlags, - CVImageBufferRef image_buffer) -{ - struct vda_context *vda_ctx = vda_hw_ctx; - - if (infoFlags & kVDADecodeInfo_FrameDropped) - vda_ctx->cv_buffer = NULL; - - if (!image_buffer) - return; - - if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer)) - return; - - vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer); -} - -static int vda_sync_decode(VTContext *ctx, struct vda_context *vda_ctx) -{ - OSStatus status; - CFDataRef coded_frame; - uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames - - coded_frame = CFDataCreate(kCFAllocatorDefault, - ctx->bitstream, - ctx->bitstream_size); - - status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); - - if (kVDADecoderNoErr == status) - status = VDADecoderFlush(vda_ctx->decoder, flush_flags); - - CFRelease(coded_frame); - - return status; -} - - -static int vda_old_h264_start_frame(AVCodecContext *avctx, - av_unused const uint8_t *buffer, - av_unused uint32_t size) -{ - VTContext *vda = avctx->internal->hwaccel_priv_data; - struct vda_context *vda_ctx = avctx->hwaccel_context; - - if (!vda_ctx->decoder) - return -1; - - vda->bitstream_size = 0; - - return 0; -} - -static int vda_old_h264_decode_slice(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) -{ - VTContext *vda = avctx->internal->hwaccel_priv_data; - struct vda_context *vda_ctx = avctx->hwaccel_context; - void *tmp; - - if (!vda_ctx->decoder) - return -1; - - tmp = av_fast_realloc(vda->bitstream, - &vda->allocated_size, - vda->bitstream_size + size + 4); - if (!tmp) - return AVERROR(ENOMEM); - - vda->bitstream = tmp; - - AV_WB32(vda->bitstream + vda->bitstream_size, size); - memcpy(vda->bitstream + vda->bitstream_size + 4, buffer, size); - - vda->bitstream_size += size + 4; - - return 0; -} - -static void vda_h264_release_buffer(void *opaque, uint8_t *data) -{ - struct vda_buffer *context = opaque; - CVPixelBufferRelease(context->cv_buffer); - av_free(context); -} - -static int vda_old_h264_end_frame(AVCodecContext *avctx) -{ - H264Context *h = avctx->priv_data; - VTContext *vda = avctx->internal->hwaccel_priv_data; - struct vda_context *vda_ctx = avctx->hwaccel_context; - AVFrame *frame = h->cur_pic_ptr->f; - struct vda_buffer *context; - AVBufferRef *buffer; - int status; - - if (!vda_ctx->decoder || !vda->bitstream) - return -1; - - status = vda_sync_decode(vda, vda_ctx); - frame->data[3] = (void*)vda_ctx->cv_buffer; - - if (status) - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); - - if (!vda_ctx->use_ref_buffer || status) - return status; - - context = av_mallocz(sizeof(*context)); - buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0); - if (!context || !buffer) { - CVPixelBufferRelease(vda_ctx->cv_buffer); - av_free(context); - return -1; - } - - context->cv_buffer = vda_ctx->cv_buffer; - frame->buf[3] = buffer; - - return status; -} - -int ff_vda_create_decoder(struct vda_context *vda_ctx, - uint8_t *extradata, - int extradata_size) -{ - OSStatus status; - CFNumberRef height; - CFNumberRef width; - CFNumberRef format; - CFDataRef avc_data; - CFMutableDictionaryRef config_info; - CFMutableDictionaryRef buffer_attributes; - CFMutableDictionaryRef io_surface_properties; - CFNumberRef cv_pix_fmt; - - vda_ctx->priv_bitstream = NULL; - vda_ctx->priv_allocated_size = 0; - - /* Each VCL NAL in the bitstream sent to the decoder - * is preceded by a 4 bytes length header. - * Change the avcC atom header if needed, to signal headers of 4 bytes. */ - if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) { - uint8_t *rw_extradata; - - if (!(rw_extradata = av_malloc(extradata_size))) - return AVERROR(ENOMEM); - - memcpy(rw_extradata, extradata, extradata_size); - - rw_extradata[4] |= 0x03; - - avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size); - - av_freep(&rw_extradata); - } else { - avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size); - } - - config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 4, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height); - width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width); - format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format); - - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); - - buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, - 2, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, - &vda_ctx->cv_pix_fmt_type); - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferPixelFormatTypeKey, - cv_pix_fmt); - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferIOSurfacePropertiesKey, - io_surface_properties); - - status = VDADecoderCreate(config_info, - buffer_attributes, - (VDADecoderOutputCallback *)vda_decoder_callback, - vda_ctx, - &vda_ctx->decoder); - - CFRelease(height); - CFRelease(width); - CFRelease(format); - CFRelease(avc_data); - CFRelease(config_info); - CFRelease(io_surface_properties); - CFRelease(cv_pix_fmt); - CFRelease(buffer_attributes); - - return status; -} - -int ff_vda_destroy_decoder(struct vda_context *vda_ctx) -{ - OSStatus status = kVDADecoderNoErr; - - if (vda_ctx->decoder) - status = VDADecoderDestroy(vda_ctx->decoder); - - return status; -} - -AVHWAccel ff_h264_vda_old_hwaccel = { - .name = "h264_vda", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_VDA_VLD, - .start_frame = vda_old_h264_start_frame, - .decode_slice = vda_old_h264_decode_slice, - .end_frame = vda_old_h264_end_frame, - .uninit = ff_videotoolbox_uninit, - .priv_data_size = sizeof(VTContext), -}; - -void ff_vda_output_callback(void *opaque, - CFDictionaryRef user_info, - OSStatus status, - uint32_t infoFlags, - CVImageBufferRef image_buffer) -{ - AVCodecContext *ctx = opaque; - VTContext *vda = ctx->internal->hwaccel_priv_data; - - - if (vda->frame) { - CVPixelBufferRelease(vda->frame); - vda->frame = NULL; - } - - if (!image_buffer) - return; - - vda->frame = CVPixelBufferRetain(image_buffer); -} - -static int vda_h264_end_frame(AVCodecContext *avctx) -{ - H264Context *h = avctx->priv_data; - VTContext *vda = avctx->internal->hwaccel_priv_data; - AVVDAContext *vda_ctx = avctx->hwaccel_context; - AVFrame *frame = h->cur_pic_ptr->f; - uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames - CFDataRef coded_frame; - OSStatus status; - - if (!vda->bitstream_size) - return AVERROR_INVALIDDATA; - - - coded_frame = CFDataCreate(kCFAllocatorDefault, - vda->bitstream, - vda->bitstream_size); - - status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); - - if (status == kVDADecoderNoErr) - status = VDADecoderFlush(vda_ctx->decoder, flush_flags); - - CFRelease(coded_frame); - - if (!vda->frame) - return AVERROR_UNKNOWN; - - if (status != kVDADecoderNoErr) { - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); - return AVERROR_UNKNOWN; - } - - return ff_videotoolbox_buffer_create(vda, frame); -} - -int ff_vda_default_init(AVCodecContext *avctx) -{ - AVVDAContext *vda_ctx = avctx->hwaccel_context; - OSStatus status = kVDADecoderNoErr; - CFNumberRef height; - CFNumberRef width; - CFNumberRef format; - CFDataRef avc_data; - CFMutableDictionaryRef config_info; - CFMutableDictionaryRef buffer_attributes; - CFMutableDictionaryRef io_surface_properties; - CFNumberRef cv_pix_fmt; - int32_t fmt = 'avc1', pix_fmt = vda_ctx->cv_pix_fmt_type; - - // kCVPixelFormatType_420YpCbCr8Planar; - - avc_data = ff_videotoolbox_avcc_extradata_create(avctx); - - config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 4, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->height); - width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->width); - format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fmt); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); - - buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, - 2, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, - &pix_fmt); - - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferPixelFormatTypeKey, - cv_pix_fmt); - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferIOSurfacePropertiesKey, - io_surface_properties); - - status = VDADecoderCreate(config_info, - buffer_attributes, - (VDADecoderOutputCallback *)ff_vda_output_callback, - avctx, - &vda_ctx->decoder); - - CFRelease(format); - CFRelease(height); - CFRelease(width); - CFRelease(avc_data); - CFRelease(config_info); - CFRelease(cv_pix_fmt); - CFRelease(io_surface_properties); - CFRelease(buffer_attributes); - - if (status != kVDADecoderNoErr) { - av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status); - } - - switch (status) { - case kVDADecoderHardwareNotSupportedErr: - case kVDADecoderFormatNotSupportedErr: - return AVERROR(ENOSYS); - case kVDADecoderConfigurationError: - return AVERROR(EINVAL); - case kVDADecoderDecoderFailedErr: - return AVERROR_INVALIDDATA; - case kVDADecoderNoErr: - return 0; - default: - return AVERROR_UNKNOWN; - } -} - -AVHWAccel ff_h264_vda_hwaccel = { - .name = "h264_vda", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_VDA, - .alloc_frame = ff_videotoolbox_alloc_frame, - .start_frame = ff_videotoolbox_h264_start_frame, - .decode_slice = ff_videotoolbox_h264_decode_slice, - .end_frame = vda_h264_end_frame, - .uninit = ff_videotoolbox_uninit, - .priv_data_size = sizeof(VTContext), -}; diff --git a/libavcodec/vda_h264_dec.c b/libavcodec/vda_h264_dec.c deleted file mode 100644 index 972bd6bbd..000000000 --- a/libavcodec/vda_h264_dec.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2012, Xidorn Quan - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 decoder via VDA - * @author Xidorn Quan - */ - -#include -#include - -#include "vda.h" -#include "h264dec.h" -#include "avcodec.h" - -#ifndef kCFCoreFoundationVersionNumber10_7 -#define kCFCoreFoundationVersionNumber10_7 635.00 -#endif - -extern AVCodec ff_h264_decoder, ff_h264_vda_decoder; - -static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = { - AV_PIX_FMT_UYVY422, - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE -}; - -static const enum AVPixelFormat vda_pixfmts[] = { - AV_PIX_FMT_UYVY422, - AV_PIX_FMT_YUYV422, - AV_PIX_FMT_NV12, - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE -}; - -typedef struct { - H264Context h264ctx; - int h264_initialized; - struct vda_context vda_ctx; - enum AVPixelFormat pix_fmt; - - /* for backing-up fields set by user. - * we have to gain full control of such fields here */ - void *hwaccel_context; - enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); - int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); -} VDADecoderContext; - -static enum AVPixelFormat get_format(struct AVCodecContext *avctx, - const enum AVPixelFormat *fmt) -{ - return AV_PIX_FMT_VDA_VLD; -} - -typedef struct { - CVPixelBufferRef cv_buffer; -} VDABufferContext; - -static void release_buffer(void *opaque, uint8_t *data) -{ - VDABufferContext *context = opaque; - CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0); - CVPixelBufferRelease(context->cv_buffer); - av_free(context); -} - -static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag) -{ - VDABufferContext *context = av_mallocz(sizeof(VDABufferContext)); - AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0); - if (!context || !buffer) { - av_free(context); - return AVERROR(ENOMEM); - } - - pic->buf[0] = buffer; - pic->data[0] = (void *)1; - return 0; -} - -static inline void set_context(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - ctx->hwaccel_context = avctx->hwaccel_context; - avctx->hwaccel_context = &ctx->vda_ctx; - ctx->get_format = avctx->get_format; - avctx->get_format = get_format; - ctx->get_buffer2 = avctx->get_buffer2; - avctx->get_buffer2 = get_buffer2; -} - -static inline void restore_context(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - avctx->hwaccel_context = ctx->hwaccel_context; - avctx->get_format = ctx->get_format; - avctx->get_buffer2 = ctx->get_buffer2; -} - -static int vdadec_decode(AVCodecContext *avctx, - void *data, int *got_frame, AVPacket *avpkt) -{ - VDADecoderContext *ctx = avctx->priv_data; - AVFrame *pic = data; - int ret; - - set_context(avctx); - ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt); - restore_context(avctx); - if (*got_frame) { - AVBufferRef *buffer = pic->buf[0]; - VDABufferContext *context = av_buffer_get_opaque(buffer); - CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3]; - - CVPixelBufferRetain(cv_buffer); - CVPixelBufferLockBaseAddress(cv_buffer, 0); - context->cv_buffer = cv_buffer; - pic->format = ctx->pix_fmt; - if (CVPixelBufferIsPlanar(cv_buffer)) { - int i, count = CVPixelBufferGetPlaneCount(cv_buffer); - av_assert0(count < 4); - for (i = 0; i < count; i++) { - pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i); - pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i); - } - } else { - pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer); - pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer); - } - } - avctx->pix_fmt = ctx->pix_fmt; - - return ret; -} - -static av_cold int vdadec_close(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - /* release buffers and decoder */ - ff_vda_destroy_decoder(&ctx->vda_ctx); - /* close H.264 decoder */ - if (ctx->h264_initialized) { - set_context(avctx); - ff_h264_decoder.close(avctx); - restore_context(avctx); - } - return 0; -} - -static av_cold int vdadec_init(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - struct vda_context *vda_ctx = &ctx->vda_ctx; - OSStatus status; - int ret, i; - - ctx->h264_initialized = 0; - - /* init pix_fmts of codec */ - if (!ff_h264_vda_decoder.pix_fmts) { - if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7) - ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7; - else - ff_h264_vda_decoder.pix_fmts = vda_pixfmts; - } - - /* init vda */ - memset(vda_ctx, 0, sizeof(struct vda_context)); - vda_ctx->width = avctx->width; - vda_ctx->height = avctx->height; - vda_ctx->format = 'avc1'; - vda_ctx->use_sync_decoding = 1; - vda_ctx->use_ref_buffer = 1; - ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts); - switch (ctx->pix_fmt) { - case AV_PIX_FMT_UYVY422: - vda_ctx->cv_pix_fmt_type = '2vuy'; - break; - case AV_PIX_FMT_YUYV422: - vda_ctx->cv_pix_fmt_type = 'yuvs'; - break; - case AV_PIX_FMT_NV12: - vda_ctx->cv_pix_fmt_type = '420v'; - break; - case AV_PIX_FMT_YUV420P: - vda_ctx->cv_pix_fmt_type = 'y420'; - break; - default: - av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt); - goto failed; - } - status = ff_vda_create_decoder(vda_ctx, - avctx->extradata, avctx->extradata_size); - if (status != kVDADecoderNoErr) { - av_log(avctx, AV_LOG_ERROR, - "Failed to init VDA decoder: %d.\n", status); - goto failed; - } - - /* init H.264 decoder */ - set_context(avctx); - ret = ff_h264_decoder.init(avctx); - restore_context(avctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n"); - goto failed; - } - ctx->h264_initialized = 1; - - for (i = 0; i < MAX_SPS_COUNT; i++) { - const SPS *sps = ctx->h264ctx.ps.sps_list[i] ? (const SPS*)ctx->h264ctx.ps.sps_list[i]->data : NULL; - if (sps && (sps->bit_depth_luma != 8 || - sps->chroma_format_idc == 2 || - sps->chroma_format_idc == 3)) { - av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n"); - goto failed; - } - } - - return 0; - -failed: - vdadec_close(avctx); - return -1; -} - -static void vdadec_flush(AVCodecContext *avctx) -{ - set_context(avctx); - ff_h264_decoder.flush(avctx); - restore_context(avctx); -} - -AVCodec ff_h264_vda_decoder = { - .name = "h264_vda", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .priv_data_size = sizeof(VDADecoderContext), - .init = vdadec_init, - .close = vdadec_close, - .decode = vdadec_decode, - .capabilities = AV_CODEC_CAP_DELAY, - .flush = vdadec_flush, - .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"), -}; diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index 4cc51cb79..1b2ec989c 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -24,23 +24,15 @@ #include #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "h264dec.h" #include "vc1.h" #include "vdpau.h" -#include "vdpau_compat.h" #include "vdpau_internal.h" // XXX: at the time of adding this ifdefery, av_assert* wasn't use outside. // When dropping it, make sure other av_assert* were not added since then. -#if FF_API_BUFS_VDPAU -#include "libavutil/avassert.h" -#endif - -#if FF_API_VDPAU -#undef NDEBUG -#include -#endif /** * @addtogroup VDPAU_Decoding @@ -119,6 +111,25 @@ int av_vdpau_get_surface_parameters(AVCodecContext *avctx, return 0; } +int ff_vdpau_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + AVHWFramesContext *hw_frames = (AVHWFramesContext*)hw_frames_ctx->data; + VdpChromaType type; + uint32_t width; + uint32_t height; + + if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height)) + return AVERROR(EINVAL); + + hw_frames->format = AV_PIX_FMT_VDPAU; + hw_frames->sw_format = avctx->sw_pix_fmt; + hw_frames->width = width; + hw_frames->height = height; + + return 0; +} + int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, int level) { @@ -136,6 +147,7 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, VdpChromaType type; uint32_t width; uint32_t height; + int ret; vdctx->width = UINT32_MAX; vdctx->height = UINT32_MAX; @@ -163,41 +175,14 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, type != VDP_CHROMA_TYPE_420) return AVERROR(ENOSYS); } else { - AVHWFramesContext *frames_ctx = NULL; + AVHWFramesContext *frames_ctx; AVVDPAUDeviceContext *dev_ctx; - // We assume the hw_frames_ctx always survives until ff_vdpau_common_uninit - // is called. This holds true as the user is not allowed to touch - // hw_device_ctx, or hw_frames_ctx after get_format (and ff_get_format - // itself also uninits before unreffing hw_frames_ctx). - if (avctx->hw_frames_ctx) { - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - } else if (avctx->hw_device_ctx) { - int ret; - - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); - if (!avctx->hw_frames_ctx) - return AVERROR(ENOMEM); - - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - frames_ctx->format = AV_PIX_FMT_VDPAU; - frames_ctx->sw_format = avctx->sw_pix_fmt; - frames_ctx->width = avctx->coded_width; - frames_ctx->height = avctx->coded_height; - - ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (ret < 0) { - av_buffer_unref(&avctx->hw_frames_ctx); - return ret; - } - } - - if (!frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "A hardware frames context is " - "required for VDPAU decoding.\n"); - return AVERROR(EINVAL); - } + ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VDPAU); + if (ret < 0) + return ret; + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; dev_ctx = frames_ctx->device_ctx->hwctx; vdctx->device = dev_ctx->device; @@ -353,18 +338,6 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, if (val < 0) return val; -#if FF_API_BUFS_VDPAU -FF_DISABLE_DEPRECATION_WARNINGS - if (hwctx) { - av_assert0(sizeof(hwctx->info) <= sizeof(pic_ctx->info)); - memcpy(&hwctx->info, &pic_ctx->info, sizeof(hwctx->info)); - hwctx->bitstream_buffers = pic_ctx->bitstream_buffers; - hwctx->bitstream_buffers_used = pic_ctx->bitstream_buffers_used; - hwctx->bitstream_buffers_allocated = pic_ctx->bitstream_buffers_allocated; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (hwctx && !hwctx->render && hwctx->render2) { status = hwctx->render2(avctx, frame, (void *)&pic_ctx->info, pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers); @@ -375,16 +348,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_freep(&pic_ctx->bitstream_buffers); -#if FF_API_BUFS_VDPAU -FF_DISABLE_DEPRECATION_WARNINGS - if (hwctx) { - hwctx->bitstream_buffers = NULL; - hwctx->bitstream_buffers_used = 0; - hwctx->bitstream_buffers_allocated = 0; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - return vdpau_error(status); } @@ -426,345 +389,6 @@ int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx, return 0; } -/* Obsolete non-hwaccel VDPAU support below... */ - -#if FF_API_VDPAU -void ff_vdpau_add_data_chunk(uint8_t *data, const uint8_t *buf, int buf_size) -{ - struct vdpau_render_state *render = (struct vdpau_render_state*)data; - assert(render); - - render->bitstream_buffers= av_fast_realloc( - render->bitstream_buffers, - &render->bitstream_buffers_allocated, - sizeof(*render->bitstream_buffers)*(render->bitstream_buffers_used + 1) - ); - - render->bitstream_buffers[render->bitstream_buffers_used].struct_version = VDP_BITSTREAM_BUFFER_VERSION; - render->bitstream_buffers[render->bitstream_buffers_used].bitstream = buf; - render->bitstream_buffers[render->bitstream_buffers_used].bitstream_bytes = buf_size; - render->bitstream_buffers_used++; -} - -#if CONFIG_H264_VDPAU_DECODER -void ff_vdpau_h264_set_reference_frames(H264Context *h) -{ - struct vdpau_render_state *render, *render_ref; - VdpReferenceFrameH264 *rf, *rf2; - H264Picture *pic; - int i, list, pic_frame_idx; - - render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0]; - assert(render); - - rf = &render->info.h264.referenceFrames[0]; -#define H264_RF_COUNT FF_ARRAY_ELEMS(render->info.h264.referenceFrames) - - for (list = 0; list < 2; ++list) { - H264Picture **lp = list ? h->long_ref : h->short_ref; - int ls = list ? 16 : h->short_ref_count; - - for (i = 0; i < ls; ++i) { - pic = lp[i]; - if (!pic || !pic->reference) - continue; - pic_frame_idx = pic->long_ref ? pic->pic_id : pic->frame_num; - - render_ref = (struct vdpau_render_state *)pic->f->data[0]; - assert(render_ref); - - rf2 = &render->info.h264.referenceFrames[0]; - while (rf2 != rf) { - if ( - (rf2->surface == render_ref->surface) - && (rf2->is_long_term == pic->long_ref) - && (rf2->frame_idx == pic_frame_idx) - ) - break; - ++rf2; - } - if (rf2 != rf) { - rf2->top_is_reference |= (pic->reference & PICT_TOP_FIELD) ? VDP_TRUE : VDP_FALSE; - rf2->bottom_is_reference |= (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE; - continue; - } - - if (rf >= &render->info.h264.referenceFrames[H264_RF_COUNT]) - continue; - - rf->surface = render_ref->surface; - rf->is_long_term = pic->long_ref; - rf->top_is_reference = (pic->reference & PICT_TOP_FIELD) ? VDP_TRUE : VDP_FALSE; - rf->bottom_is_reference = (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE; - rf->field_order_cnt[0] = pic->field_poc[0]; - rf->field_order_cnt[1] = pic->field_poc[1]; - rf->frame_idx = pic_frame_idx; - - ++rf; - } - } - - for (; rf < &render->info.h264.referenceFrames[H264_RF_COUNT]; ++rf) { - rf->surface = VDP_INVALID_HANDLE; - rf->is_long_term = 0; - rf->top_is_reference = 0; - rf->bottom_is_reference = 0; - rf->field_order_cnt[0] = 0; - rf->field_order_cnt[1] = 0; - rf->frame_idx = 0; - } -} - -void ff_vdpau_h264_picture_start(H264Context *h) -{ - struct vdpau_render_state *render; - int i; - - render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0]; - assert(render); - - for (i = 0; i < 2; ++i) { - int foc = h->cur_pic_ptr->field_poc[i]; - if (foc == INT_MAX) - foc = 0; - render->info.h264.field_order_cnt[i] = foc; - } - - render->info.h264.frame_num = h->poc.frame_num; -} - -void ff_vdpau_h264_picture_complete(H264Context *h) -{ - struct vdpau_render_state *render; - - render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0]; - assert(render); - - render->info.h264.slice_count = h->current_slice; - if (render->info.h264.slice_count < 1) - return; - - render->info.h264.is_reference = (h->cur_pic_ptr->reference & 3) ? VDP_TRUE : VDP_FALSE; - render->info.h264.field_pic_flag = h->picture_structure != PICT_FRAME; - render->info.h264.bottom_field_flag = h->picture_structure == PICT_BOTTOM_FIELD; - render->info.h264.num_ref_frames = h->ps.sps->ref_frame_count; - render->info.h264.mb_adaptive_frame_field_flag = h->ps.sps->mb_aff && !render->info.h264.field_pic_flag; - render->info.h264.constrained_intra_pred_flag = h->ps.pps->constrained_intra_pred; - render->info.h264.weighted_pred_flag = h->ps.pps->weighted_pred; - render->info.h264.weighted_bipred_idc = h->ps.pps->weighted_bipred_idc; - render->info.h264.frame_mbs_only_flag = h->ps.sps->frame_mbs_only_flag; - render->info.h264.transform_8x8_mode_flag = h->ps.pps->transform_8x8_mode; - render->info.h264.chroma_qp_index_offset = h->ps.pps->chroma_qp_index_offset[0]; - render->info.h264.second_chroma_qp_index_offset = h->ps.pps->chroma_qp_index_offset[1]; - render->info.h264.pic_init_qp_minus26 = h->ps.pps->init_qp - 26; - render->info.h264.num_ref_idx_l0_active_minus1 = h->ps.pps->ref_count[0] - 1; - render->info.h264.num_ref_idx_l1_active_minus1 = h->ps.pps->ref_count[1] - 1; - render->info.h264.log2_max_frame_num_minus4 = h->ps.sps->log2_max_frame_num - 4; - render->info.h264.pic_order_cnt_type = h->ps.sps->poc_type; - render->info.h264.log2_max_pic_order_cnt_lsb_minus4 = h->ps.sps->poc_type ? 0 : h->ps.sps->log2_max_poc_lsb - 4; - render->info.h264.delta_pic_order_always_zero_flag = h->ps.sps->delta_pic_order_always_zero_flag; - render->info.h264.direct_8x8_inference_flag = h->ps.sps->direct_8x8_inference_flag; - render->info.h264.entropy_coding_mode_flag = h->ps.pps->cabac; - render->info.h264.pic_order_present_flag = h->ps.pps->pic_order_present; - render->info.h264.deblocking_filter_control_present_flag = h->ps.pps->deblocking_filter_parameters_present; - render->info.h264.redundant_pic_cnt_present_flag = h->ps.pps->redundant_pic_cnt_present; - memcpy(render->info.h264.scaling_lists_4x4, h->ps.pps->scaling_matrix4, sizeof(render->info.h264.scaling_lists_4x4)); - memcpy(render->info.h264.scaling_lists_8x8[0], h->ps.pps->scaling_matrix8[0], sizeof(render->info.h264.scaling_lists_8x8[0])); - memcpy(render->info.h264.scaling_lists_8x8[1], h->ps.pps->scaling_matrix8[3], sizeof(render->info.h264.scaling_lists_8x8[0])); - - ff_h264_draw_horiz_band(h, &h->slice_ctx[0], 0, h->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* CONFIG_H264_VDPAU_DECODER */ - -#if CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER -void ff_vdpau_mpeg_picture_complete(MpegEncContext *s, const uint8_t *buf, - int buf_size, int slice_count) -{ - struct vdpau_render_state *render, *last, *next; - int i; - - if (!s->current_picture_ptr) return; - - render = (struct vdpau_render_state *)s->current_picture_ptr->f->data[0]; - assert(render); - - /* fill VdpPictureInfoMPEG1Or2 struct */ - render->info.mpeg.picture_structure = s->picture_structure; - render->info.mpeg.picture_coding_type = s->pict_type; - render->info.mpeg.intra_dc_precision = s->intra_dc_precision; - render->info.mpeg.frame_pred_frame_dct = s->frame_pred_frame_dct; - render->info.mpeg.concealment_motion_vectors = s->concealment_motion_vectors; - render->info.mpeg.intra_vlc_format = s->intra_vlc_format; - render->info.mpeg.alternate_scan = s->alternate_scan; - render->info.mpeg.q_scale_type = s->q_scale_type; - render->info.mpeg.top_field_first = s->top_field_first; - render->info.mpeg.full_pel_forward_vector = s->full_pel[0]; // MPEG-1 only. Set 0 for MPEG-2 - render->info.mpeg.full_pel_backward_vector = s->full_pel[1]; // MPEG-1 only. Set 0 for MPEG-2 - render->info.mpeg.f_code[0][0] = s->mpeg_f_code[0][0]; // For MPEG-1 fill both horiz. & vert. - render->info.mpeg.f_code[0][1] = s->mpeg_f_code[0][1]; - render->info.mpeg.f_code[1][0] = s->mpeg_f_code[1][0]; - render->info.mpeg.f_code[1][1] = s->mpeg_f_code[1][1]; - for (i = 0; i < 64; ++i) { - render->info.mpeg.intra_quantizer_matrix[i] = s->intra_matrix[i]; - render->info.mpeg.non_intra_quantizer_matrix[i] = s->inter_matrix[i]; - } - - render->info.mpeg.forward_reference = VDP_INVALID_HANDLE; - render->info.mpeg.backward_reference = VDP_INVALID_HANDLE; - - switch(s->pict_type){ - case AV_PICTURE_TYPE_B: - next = (struct vdpau_render_state *)s->next_picture.f->data[0]; - assert(next); - render->info.mpeg.backward_reference = next->surface; - // no return here, going to set forward prediction - case AV_PICTURE_TYPE_P: - last = (struct vdpau_render_state *)s->last_picture.f->data[0]; - if (!last) // FIXME: Does this test make sense? - last = render; // predict second field from the first - render->info.mpeg.forward_reference = last->surface; - } - - ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size); - - render->info.mpeg.slice_count = slice_count; - - if (slice_count) - ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER */ - -#if CONFIG_VC1_VDPAU_DECODER -void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf, - int buf_size) -{ - VC1Context *v = s->avctx->priv_data; - struct vdpau_render_state *render, *last, *next; - - render = (struct vdpau_render_state *)s->current_picture.f->data[0]; - assert(render); - - /* fill LvPictureInfoVC1 struct */ - render->info.vc1.frame_coding_mode = v->fcm ? v->fcm + 1 : 0; - render->info.vc1.postprocflag = v->postprocflag; - render->info.vc1.pulldown = v->broadcast; - render->info.vc1.interlace = v->interlace; - render->info.vc1.tfcntrflag = v->tfcntrflag; - render->info.vc1.finterpflag = v->finterpflag; - render->info.vc1.psf = v->psf; - render->info.vc1.dquant = v->dquant; - render->info.vc1.panscan_flag = v->panscanflag; - render->info.vc1.refdist_flag = v->refdist_flag; - render->info.vc1.quantizer = v->quantizer_mode; - render->info.vc1.extended_mv = v->extended_mv; - render->info.vc1.extended_dmv = v->extended_dmv; - render->info.vc1.overlap = v->overlap; - render->info.vc1.vstransform = v->vstransform; - render->info.vc1.loopfilter = v->s.loop_filter; - render->info.vc1.fastuvmc = v->fastuvmc; - render->info.vc1.range_mapy_flag = v->range_mapy_flag; - render->info.vc1.range_mapy = v->range_mapy; - render->info.vc1.range_mapuv_flag = v->range_mapuv_flag; - render->info.vc1.range_mapuv = v->range_mapuv; - /* Specific to simple/main profile only */ - render->info.vc1.multires = v->multires; - render->info.vc1.syncmarker = v->resync_marker; - render->info.vc1.rangered = v->rangered | (v->rangeredfrm << 1); - render->info.vc1.maxbframes = v->s.max_b_frames; - - render->info.vc1.deblockEnable = v->postprocflag & 1; - render->info.vc1.pquant = v->pq; - - render->info.vc1.forward_reference = VDP_INVALID_HANDLE; - render->info.vc1.backward_reference = VDP_INVALID_HANDLE; - - if (v->bi_type) - render->info.vc1.picture_type = 4; - else - render->info.vc1.picture_type = s->pict_type - 1 + s->pict_type / 3; - - switch(s->pict_type){ - case AV_PICTURE_TYPE_B: - next = (struct vdpau_render_state *)s->next_picture.f->data[0]; - assert(next); - render->info.vc1.backward_reference = next->surface; - // no break here, going to set forward prediction - case AV_PICTURE_TYPE_P: - last = (struct vdpau_render_state *)s->last_picture.f->data[0]; - if (!last) // FIXME: Does this test make sense? - last = render; // predict second field from the first - render->info.vc1.forward_reference = last->surface; - } - - ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size); - - render->info.vc1.slice_count = 1; - - ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* (CONFIG_VC1_VDPAU_DECODER */ - -#if CONFIG_MPEG4_VDPAU_DECODER -void ff_vdpau_mpeg4_decode_picture(Mpeg4DecContext *ctx, const uint8_t *buf, - int buf_size) -{ - MpegEncContext *s = &ctx->m; - struct vdpau_render_state *render, *last, *next; - int i; - - if (!s->current_picture_ptr) return; - - render = (struct vdpau_render_state *)s->current_picture_ptr->f->data[0]; - assert(render); - - /* fill VdpPictureInfoMPEG4Part2 struct */ - render->info.mpeg4.trd[0] = s->pp_time; - render->info.mpeg4.trb[0] = s->pb_time; - render->info.mpeg4.trd[1] = s->pp_field_time >> 1; - render->info.mpeg4.trb[1] = s->pb_field_time >> 1; - render->info.mpeg4.vop_time_increment_resolution = s->avctx->time_base.den; - render->info.mpeg4.vop_coding_type = 0; - render->info.mpeg4.vop_fcode_forward = s->f_code; - render->info.mpeg4.vop_fcode_backward = s->b_code; - render->info.mpeg4.resync_marker_disable = !ctx->resync_marker; - render->info.mpeg4.interlaced = !s->progressive_sequence; - render->info.mpeg4.quant_type = s->mpeg_quant; - render->info.mpeg4.quarter_sample = s->quarter_sample; - render->info.mpeg4.short_video_header = s->avctx->codec->id == AV_CODEC_ID_H263; - render->info.mpeg4.rounding_control = s->no_rounding; - render->info.mpeg4.alternate_vertical_scan_flag = s->alternate_scan; - render->info.mpeg4.top_field_first = s->top_field_first; - for (i = 0; i < 64; ++i) { - render->info.mpeg4.intra_quantizer_matrix[i] = s->intra_matrix[i]; - render->info.mpeg4.non_intra_quantizer_matrix[i] = s->inter_matrix[i]; - } - render->info.mpeg4.forward_reference = VDP_INVALID_HANDLE; - render->info.mpeg4.backward_reference = VDP_INVALID_HANDLE; - - switch (s->pict_type) { - case AV_PICTURE_TYPE_B: - next = (struct vdpau_render_state *)s->next_picture.f->data[0]; - assert(next); - render->info.mpeg4.backward_reference = next->surface; - render->info.mpeg4.vop_coding_type = 2; - // no break here, going to set forward prediction - case AV_PICTURE_TYPE_P: - last = (struct vdpau_render_state *)s->last_picture.f->data[0]; - assert(last); - render->info.mpeg4.forward_reference = last->surface; - } - - ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size); - - ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* CONFIG_MPEG4_VDPAU_DECODER */ -#endif /* FF_API_VDPAU */ - #if FF_API_VDPAU_PROFILE int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile) { diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h index 855d387d9..4d9994336 100644 --- a/libavcodec/vdpau.h +++ b/libavcodec/vdpau.h @@ -57,15 +57,6 @@ #include "avcodec.h" #include "version.h" -#if FF_API_BUFS_VDPAU -union AVVDPAUPictureInfo { - VdpPictureInfoH264 h264; - VdpPictureInfoMPEG1Or2 mpeg; - VdpPictureInfoVC1 vc1; - VdpPictureInfoMPEG4Part2 mpeg4; -}; -#endif - struct AVCodecContext; struct AVFrame; @@ -102,40 +93,6 @@ typedef struct AVVDPAUContext { */ VdpDecoderRender *render; -#if FF_API_BUFS_VDPAU - /** - * VDPAU picture information - * - * Set by libavcodec. - */ - attribute_deprecated - union AVVDPAUPictureInfo info; - - /** - * Allocated size of the bitstream_buffers table. - * - * Set by libavcodec. - */ - attribute_deprecated - int bitstream_buffers_allocated; - - /** - * Useful bitstream buffers in the bitstream buffers table. - * - * Set by libavcodec. - */ - attribute_deprecated - int bitstream_buffers_used; - - /** - * Table of bitstream buffers. - * The user is responsible for freeing this buffer using av_freep(). - * - * Set by libavcodec. - */ - attribute_deprecated - VdpBitstreamBuffer *bitstream_buffers; -#endif AVVDPAU_Render2 render2; } AVVDPAUContext; @@ -214,40 +171,6 @@ attribute_deprecated int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); #endif -#if FF_API_CAP_VDPAU -/** @brief The videoSurface is used for rendering. */ -#define FF_VDPAU_STATE_USED_FOR_RENDER 1 - -/** - * @brief The videoSurface is needed for reference/prediction. - * The codec manipulates this. - */ -#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 - -/** - * @brief This structure is used as a callback between the FFmpeg - * decoder (vd_) and presentation (vo_) module. - * This is used for defining a video frame containing surface, - * picture parameter, bitstream information etc which are passed - * between the FFmpeg decoder and its clients. - */ -struct vdpau_render_state { - VdpVideoSurface surface; ///< Used as rendered surface, never changed. - - int state; ///< Holds FF_VDPAU_STATE_* values. - - /** picture parameter information for all supported codecs */ - union AVVDPAUPictureInfo info; - - /** Describe size/location of the compressed video data. - Set to 0 when freeing bitstream_buffers. */ - int bitstream_buffers_allocated; - int bitstream_buffers_used; - /** The user is responsible for freeing this buffer using av_freep(). */ - VdpBitstreamBuffer *bitstream_buffers; -}; -#endif - /* @}*/ #endif /* AVCODEC_VDPAU_H */ diff --git a/libavcodec/vdpau_compat.h b/libavcodec/vdpau_compat.h deleted file mode 100644 index 768acce78..000000000 --- a/libavcodec/vdpau_compat.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Video Decode and Presentation API for UNIX (VDPAU) is used for - * HW decode acceleration for 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_COMPAT_H -#define AVCODEC_VDPAU_COMPAT_H - -#include - -#include "h264dec.h" -#include "mpeg4video.h" - -void ff_vdpau_add_data_chunk(uint8_t *data, const uint8_t *buf, - int buf_size); - -void ff_vdpau_mpeg_picture_complete(MpegEncContext *s, const uint8_t *buf, - int buf_size, int slice_count); - -void ff_vdpau_h264_picture_start(H264Context *h); -void ff_vdpau_h264_set_reference_frames(H264Context *h); -void ff_vdpau_h264_picture_complete(H264Context *h); - -void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf, - int buf_size); - -void ff_vdpau_mpeg4_decode_picture(Mpeg4DecContext *s, const uint8_t *buf, - int buf_size); - -#endif /* AVCODEC_VDPAU_COMPAT_H */ diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c index be6ba7143..2a260f76a 100644 --- a/libavcodec/vdpau_h264.c +++ b/libavcodec/vdpau_h264.c @@ -262,7 +262,7 @@ static int vdpau_h264_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, level); } -AVHWAccel ff_h264_vdpau_hwaccel = { +const AVHWAccel ff_h264_vdpau_hwaccel = { .name = "h264_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -273,6 +273,7 @@ AVHWAccel ff_h264_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_h264_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index fcdf4b274..421135bce 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -413,7 +413,7 @@ static int vdpau_hevc_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, level); } -AVHWAccel ff_hevc_vdpau_hwaccel = { +const AVHWAccel ff_hevc_vdpau_hwaccel = { .name = "hevc_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -424,6 +424,7 @@ AVHWAccel ff_hevc_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_hevc_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h index 30d01af65..4d63e50b1 100644 --- a/libavcodec/vdpau_internal.h +++ b/libavcodec/vdpau_internal.h @@ -119,5 +119,7 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx); int ff_vdpau_add_buffer(struct vdpau_picture_context *pic, const uint8_t *buf, uint32_t buf_size); +int ff_vdpau_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx); #endif /* AVCODEC_VDPAU_INTERNAL_H */ diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c index b657007ee..d286e7e57 100644 --- a/libavcodec/vdpau_mpeg12.c +++ b/libavcodec/vdpau_mpeg12.c @@ -103,7 +103,7 @@ static int vdpau_mpeg1_init(AVCodecContext *avctx) VDP_DECODER_LEVEL_MPEG1_NA); } -AVHWAccel ff_mpeg1_vdpau_hwaccel = { +const AVHWAccel ff_mpeg1_vdpau_hwaccel = { .name = "mpeg1_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG1VIDEO, @@ -138,7 +138,7 @@ static int vdpau_mpeg2_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, VDP_DECODER_LEVEL_MPEG2_HL); } -AVHWAccel ff_mpeg2_vdpau_hwaccel = { +const AVHWAccel ff_mpeg2_vdpau_hwaccel = { .name = "mpeg2_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -149,6 +149,7 @@ AVHWAccel ff_mpeg2_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_mpeg2_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c index bbdd843a4..96f83026a 100644 --- a/libavcodec/vdpau_mpeg4.c +++ b/libavcodec/vdpau_mpeg4.c @@ -110,7 +110,7 @@ static int vdpau_mpeg4_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, avctx->level); } -AVHWAccel ff_mpeg4_vdpau_hwaccel = { +const AVHWAccel ff_mpeg4_vdpau_hwaccel = { .name = "mpeg4_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG4, @@ -121,6 +121,7 @@ AVHWAccel ff_mpeg4_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_mpeg4_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c index 665a2333f..671baf96b 100644 --- a/libavcodec/vdpau_vc1.c +++ b/libavcodec/vdpau_vc1.c @@ -136,7 +136,7 @@ static int vdpau_vc1_init(AVCodecContext *avctx) } #if CONFIG_WMV3_VDPAU_HWACCEL -AVHWAccel ff_wmv3_vdpau_hwaccel = { +const AVHWAccel ff_wmv3_vdpau_hwaccel = { .name = "wm3_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -147,12 +147,13 @@ AVHWAccel ff_wmv3_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_vc1_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; #endif -AVHWAccel ff_vc1_vdpau_hwaccel = { +const AVHWAccel ff_vc1_vdpau_hwaccel = { .name = "vc1_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -163,6 +164,7 @@ AVHWAccel ff_vc1_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_vc1_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/version.h b/libavcodec/version.h index 10d9ac4eb..47a15d52b 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -27,8 +27,8 @@ #include "libavutil/version.h" -#define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 107 +#define LIBAVCODEC_VERSION_MAJOR 58 +#define LIBAVCODEC_VERSION_MINOR 9 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -51,136 +51,18 @@ * at once through the bump. This improves the git bisect-ability of the change. */ -#ifndef FF_API_VIMA_DECODER -#define FF_API_VIMA_DECODER (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AUDIO_CONVERT -#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AVCODEC_RESAMPLE -#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT -#endif -#ifndef FF_API_MISSING_SAMPLE -#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif #ifndef FF_API_LOWRES -#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_CAP_VDPAU -#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_BUFS_VDPAU -#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_VOXWARE -#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_SET_DIMENSIONS -#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 58) +#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_AC_VLC -#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_OLD_MSMPEG4 -#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ASPECT_EXTENDED -#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ARCH_ALPHA -#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_XVMC -#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ERROR_RATE -#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_QSCALE_TYPE -#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MB_TYPE -#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MAX_BFRAMES -#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_NEG_LINESIZES -#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_EMU_EDGE -#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ARCH_SH4 -#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ARCH_SPARC -#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_UNUSED_MEMBERS -#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_IDCT_XVIDMMX -#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_INPUT_PRESERVED -#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_NORMALIZE_AQP -#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_GMC -#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MV0 -#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_CODEC_NAME -#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AFD -#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_VISMV -/* XXX: don't forget to drop the -vismv documentation */ -#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AUDIOENC_DELAY -#define FF_API_AUDIOENC_DELAY (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_VAAPI_CONTEXT -#define FF_API_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MERGE_SD -#define FF_API_MERGE_SD (LIBAVCODEC_VERSION_MAJOR < 58) -#endif #ifndef FF_API_AVCTX_TIMEBASE #define FF_API_AVCTX_TIMEBASE (LIBAVCODEC_VERSION_MAJOR < 59) #endif -#ifndef FF_API_MPV_OPT -#define FF_API_MPV_OPT (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_STREAM_CODEC_TAG -#define FF_API_STREAM_CODEC_TAG (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_QUANT_BIAS -#define FF_API_QUANT_BIAS (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_RC_STRATEGY -#define FF_API_RC_STRATEGY (LIBAVCODEC_VERSION_MAJOR < 59) -#endif #ifndef FF_API_CODED_FRAME #define FF_API_CODED_FRAME (LIBAVCODEC_VERSION_MAJOR < 59) #endif -#ifndef FF_API_MOTION_EST -#define FF_API_MOTION_EST (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_WITHOUT_PREFIX -#define FF_API_WITHOUT_PREFIX (LIBAVCODEC_VERSION_MAJOR < 59) -#endif #ifndef FF_API_SIDEDATA_ONLY_PKT #define FF_API_SIDEDATA_ONLY_PKT (LIBAVCODEC_VERSION_MAJOR < 59) #endif @@ -238,6 +120,15 @@ #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 #endif /* AVCODEC_VERSION_H */ diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index ec8b6d885..afec1edf3 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -21,16 +21,13 @@ */ #include "config.h" -#if CONFIG_VIDEOTOOLBOX -# include "videotoolbox.h" -# include "libavutil/hwcontext_videotoolbox.h" -#else -# include "vda.h" -#endif -#include "vda_vt_internal.h" +#include "videotoolbox.h" +#include "libavutil/hwcontext_videotoolbox.h" +#include "vt_internal.h" #include "libavutil/avutil.h" #include "libavutil/hwcontext.h" #include "bytestream.h" +#include "decode.h" #include "h264dec.h" #include "hevcdec.h" #include "mpegvideo.h" @@ -74,6 +71,10 @@ static int videotoolbox_buffer_copy(VTContext *vtctx, int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame) { + int ret = ff_attach_decode_data(frame); + if (ret < 0) + return ret; + frame->width = avctx->width; frame->height = avctx->height; frame->format = avctx->pix_fmt; @@ -89,7 +90,8 @@ int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame) CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) { - H264Context *h = avctx->priv_data; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + H264Context *h = avctx->priv_data; CFDataRef data = NULL; uint8_t *p; int vt_extradata_size = 6 + 2 + h->ps.sps->data_size + 3 + h->ps.pps->data_size; @@ -115,6 +117,11 @@ CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) p += 3 + h->ps.pps->data_size; av_assert0(p - vt_extradata == vt_extradata_size); + // save sps header (profile/level) used to create decoder session, + // so we can detect changes and recreate it. + if (vtctx) + memcpy(vtctx->sps, h->ps.sps->data + 1, 3); + data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size); av_free(vt_extradata); return data; @@ -135,7 +142,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) int vt_extradata_size = 23 + 5 + vps->data_size + 5 + sps->data_size + 3; uint8_t *vt_extradata; - for (i = 0; i < MAX_PPS_COUNT; i++) { + for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { if (h->ps.pps_list[i]) { const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; vt_extradata_size += 2 + pps->data_size; @@ -262,7 +269,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) HEVC_NAL_PPS & 0x3f); AV_WB16(p + 1, num_pps); p += 3; - for (i = 0; i < MAX_PPS_COUNT; i++) { + for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { if (h->ps.pps_list[i]) { const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; AV_WB16(p, pps->data_size); @@ -304,8 +311,6 @@ int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, VTContext *vtctx = avctx->internal->hwaccel_priv_data; H264Context *h = avctx->priv_data; - vtctx->bitstream_size = 0; - if (h->is_avc == 1) { return videotoolbox_buffer_copy(vtctx, buffer, size); } @@ -313,6 +318,29 @@ int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, return 0; } +static int videotoolbox_h264_decode_params(AVCodecContext *avctx, + int type, + const uint8_t *buffer, + uint32_t size) +{ + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + H264Context *h = avctx->priv_data; + + // save sps header (profile/level) used to create decoder session + if (!vtctx->sps[0]) + memcpy(vtctx->sps, h->ps.sps->data + 1, 3); + + if (type == H264_NAL_SPS) { + if (size > 4 && memcmp(vtctx->sps, buffer + 1, 3) != 0) { + vtctx->reconfig_needed = true; + memcpy(vtctx->sps, buffer + 1, 3); + } + } + + // pass-through SPS/PPS changes to the decoder + return ff_videotoolbox_h264_decode_slice(avctx, buffer, size); +} + int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) @@ -578,123 +606,25 @@ static OSStatus videotoolbox_session_decode_frame(AVCodecContext *avctx) return status; } -static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) +static CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecType codec_type, + CFDictionaryRef decoder_spec, + int width, + int height) { - int status; - AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); - VTContext *vtctx = avctx->internal->hwaccel_priv_data; + CMFormatDescriptionRef cm_fmt_desc; + OSStatus status; - if (!videotoolbox->session || !vtctx->bitstream) - return AVERROR_INVALIDDATA; + status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, + codec_type, + width, + height, + decoder_spec, // Dictionary of extension + &cm_fmt_desc); - status = videotoolbox_session_decode_frame(avctx); + if (status) + return NULL; - if (status) { - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); - return AVERROR_UNKNOWN; - } - - if (!vtctx->frame) - return AVERROR_UNKNOWN; - - return videotoolbox_buffer_create(avctx, frame); -} - -static int videotoolbox_h264_end_frame(AVCodecContext *avctx) -{ - H264Context *h = avctx->priv_data; - AVFrame *frame = h->cur_pic_ptr->f; - - return videotoolbox_common_end_frame(avctx, frame); -} - -static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) -{ - HEVCContext *h = avctx->priv_data; - AVFrame *frame = h->ref->frame; - VTContext *vtctx = avctx->internal->hwaccel_priv_data; - int ret; - - ret = videotoolbox_common_end_frame(avctx, frame); - vtctx->bitstream_size = 0; - return ret; -} - -static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) -{ - VTContext *vtctx = avctx->internal->hwaccel_priv_data; - - return videotoolbox_buffer_copy(vtctx, buffer, size); -} - -static int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) -{ - return 0; -} - -static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) -{ - MpegEncContext *s = avctx->priv_data; - AVFrame *frame = s->current_picture_ptr->f; - - return videotoolbox_common_end_frame(avctx, frame); -} - -static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec_type, - AVCodecContext *avctx) -{ - CFMutableDictionaryRef config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - CFDictionarySetValue(config_info, - kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, - kCFBooleanTrue); - - if (avctx->extradata_size) { - CFMutableDictionaryRef avc_info; - CFDataRef data = NULL; - - avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 1, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - switch (codec_type) { - case kCMVideoCodecType_MPEG4Video : - data = videotoolbox_esds_extradata_create(avctx); - if (data) - CFDictionarySetValue(avc_info, CFSTR("esds"), data); - break; - case kCMVideoCodecType_H264 : - data = ff_videotoolbox_avcc_extradata_create(avctx); - if (data) - CFDictionarySetValue(avc_info, CFSTR("avcC"), data); - break; - case kCMVideoCodecType_HEVC : - data = ff_videotoolbox_hvcc_extradata_create(avctx); - if (data) - CFDictionarySetValue(avc_info, CFSTR("hvcC"), data); - break; - default: - break; - } - - CFDictionarySetValue(config_info, - kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, - avc_info); - - if (data) - CFRelease(data); - - CFRelease(avc_info); - } - return config_info; + return cm_fmt_desc; } static CFDictionaryRef videotoolbox_buffer_attributes_create(int width, @@ -739,28 +669,59 @@ static CFDictionaryRef videotoolbox_buffer_attributes_create(int width, return buffer_attributes; } -static CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecType codec_type, - CFDictionaryRef decoder_spec, - int width, - int height) +static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec_type, + AVCodecContext *avctx) { - CMFormatDescriptionRef cm_fmt_desc; - OSStatus status; + CFMutableDictionaryRef config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); - status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, - codec_type, - width, - height, - decoder_spec, // Dictionary of extension - &cm_fmt_desc); + CFDictionarySetValue(config_info, + kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, + kCFBooleanTrue); - if (status) - return NULL; + CFMutableDictionaryRef avc_info; + CFDataRef data = NULL; - return cm_fmt_desc; + avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + switch (codec_type) { + case kCMVideoCodecType_MPEG4Video : + if (avctx->extradata_size) + data = videotoolbox_esds_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("esds"), data); + break; + case kCMVideoCodecType_H264 : + data = ff_videotoolbox_avcc_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("avcC"), data); + break; + case kCMVideoCodecType_HEVC : + data = ff_videotoolbox_hvcc_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("hvcC"), data); + break; + default: + break; + } + + CFDictionarySetValue(config_info, + kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, + avc_info); + + if (data) + CFRelease(data); + + CFRelease(avc_info); + return config_info; } -static int videotoolbox_default_init(AVCodecContext *avctx) +static int videotoolbox_start(AVCodecContext *avctx) { AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); OSStatus status; @@ -798,6 +759,11 @@ static int videotoolbox_default_init(AVCodecContext *avctx) decoder_spec = videotoolbox_decoder_config_create(videotoolbox->cm_codec_type, avctx); + if (!decoder_spec) { + av_log(avctx, AV_LOG_ERROR, "decoder specification creation failed\n"); + return -1; + } + videotoolbox->cm_fmt_desc = videotoolbox_format_desc_create(videotoolbox->cm_codec_type, decoder_spec, avctx->width, @@ -839,7 +805,7 @@ static int videotoolbox_default_init(AVCodecContext *avctx) case kVTVideoDecoderMalfunctionErr: av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox malfunction.\n"); return AVERROR(EINVAL); - case kVTVideoDecoderBadDataErr : + case kVTVideoDecoderBadDataErr: av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox reported invalid data.\n"); return AVERROR_INVALIDDATA; case 0: @@ -850,19 +816,123 @@ static int videotoolbox_default_init(AVCodecContext *avctx) } } -static void videotoolbox_default_free(AVCodecContext *avctx) +static void videotoolbox_stop(AVCodecContext *avctx) { AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); + if (!videotoolbox) + return; - if (videotoolbox) { - if (videotoolbox->cm_fmt_desc) - CFRelease(videotoolbox->cm_fmt_desc); + if (videotoolbox->cm_fmt_desc) { + CFRelease(videotoolbox->cm_fmt_desc); + videotoolbox->cm_fmt_desc = NULL; + } - if (videotoolbox->session) { - VTDecompressionSessionInvalidate(videotoolbox->session); - CFRelease(videotoolbox->session); + if (videotoolbox->session) { + VTDecompressionSessionInvalidate(videotoolbox->session); + CFRelease(videotoolbox->session); + videotoolbox->session = NULL; + } +} + +static const char *videotoolbox_error_string(OSStatus status) +{ + switch (status) { + case kVTVideoDecoderBadDataErr: + return "bad data"; + case kVTVideoDecoderMalfunctionErr: + return "decoder malfunction"; + case kVTInvalidSessionErr: + return "invalid session"; + } + return "unknown"; +} + +static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) +{ + OSStatus status; + AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + + if (vtctx->reconfig_needed == true) { + vtctx->reconfig_needed = false; + av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder needs reconfig, restarting..\n"); + videotoolbox_stop(avctx); + if (videotoolbox_start(avctx) != 0) { + return AVERROR_EXTERNAL; } } + + if (!videotoolbox->session || !vtctx->bitstream || !vtctx->bitstream_size) + return AVERROR_INVALIDDATA; + + status = videotoolbox_session_decode_frame(avctx); + if (status != noErr) { + if (status == kVTVideoDecoderMalfunctionErr || status == kVTInvalidSessionErr) + vtctx->reconfig_needed = true; + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%s, %d)\n", videotoolbox_error_string(status), (int)status); + return AVERROR_UNKNOWN; + } + + if (!vtctx->frame) { + vtctx->reconfig_needed = true; + return AVERROR_UNKNOWN; + } + + return videotoolbox_buffer_create(avctx, frame); +} + +static int videotoolbox_h264_end_frame(AVCodecContext *avctx) +{ + H264Context *h = avctx->priv_data; + AVFrame *frame = h->cur_pic_ptr->f; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + int ret = videotoolbox_common_end_frame(avctx, frame); + vtctx->bitstream_size = 0; + return ret; +} + +static int videotoolbox_hevc_decode_params(AVCodecContext *avctx, + int type, + const uint8_t *buffer, + uint32_t size) +{ + return ff_videotoolbox_h264_decode_slice(avctx, buffer, size); +} + +static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) +{ + HEVCContext *h = avctx->priv_data; + AVFrame *frame = h->ref->frame; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + int ret; + + ret = videotoolbox_common_end_frame(avctx, frame); + vtctx->bitstream_size = 0; + return ret; +} + +static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + + return videotoolbox_buffer_copy(vtctx, buffer, size); +} + +static int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + return 0; +} + +static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) +{ + MpegEncContext *s = avctx->priv_data; + AVFrame *frame = s->current_picture_ptr->f; + + return videotoolbox_common_end_frame(avctx, frame); } static int videotoolbox_uninit(AVCodecContext *avctx) @@ -874,7 +944,7 @@ static int videotoolbox_uninit(AVCodecContext *avctx) ff_videotoolbox_uninit(avctx); if (vtctx->vt_ctx) - videotoolbox_default_free(avctx); + videotoolbox_stop(avctx); av_buffer_unref(&vtctx->cached_hw_frames_ctx); av_freep(&vtctx->vt_ctx); @@ -940,7 +1010,7 @@ static int videotoolbox_common_init(AVCodecContext *avctx) goto fail; } - err = videotoolbox_default_init(avctx); + err = videotoolbox_start(avctx); if (err < 0) goto fail; @@ -951,7 +1021,20 @@ fail: return err; } -AVHWAccel ff_h263_videotoolbox_hwaccel = { +static int videotoolbox_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; + + frames_ctx->format = AV_PIX_FMT_VIDEOTOOLBOX; + frames_ctx->width = avctx->coded_width; + frames_ctx->height = avctx->coded_height; + frames_ctx->sw_format = AV_PIX_FMT_NV12; + + return 0; +} + +const AVHWAccel ff_h263_videotoolbox_hwaccel = { .name = "h263_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H263, @@ -960,12 +1043,13 @@ AVHWAccel ff_h263_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_hevc_videotoolbox_hwaccel = { +const AVHWAccel ff_hevc_videotoolbox_hwaccel = { .name = "hevc_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -973,13 +1057,15 @@ AVHWAccel ff_hevc_videotoolbox_hwaccel = { .alloc_frame = ff_videotoolbox_alloc_frame, .start_frame = ff_videotoolbox_h264_start_frame, .decode_slice = ff_videotoolbox_h264_decode_slice, + .decode_params = videotoolbox_hevc_decode_params, .end_frame = videotoolbox_hevc_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = ff_videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_h264_videotoolbox_hwaccel = { +const AVHWAccel ff_h264_videotoolbox_hwaccel = { .name = "h264_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -987,13 +1073,15 @@ AVHWAccel ff_h264_videotoolbox_hwaccel = { .alloc_frame = ff_videotoolbox_alloc_frame, .start_frame = ff_videotoolbox_h264_start_frame, .decode_slice = ff_videotoolbox_h264_decode_slice, + .decode_params = videotoolbox_h264_decode_params, .end_frame = videotoolbox_h264_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_mpeg1_videotoolbox_hwaccel = { +const AVHWAccel ff_mpeg1_videotoolbox_hwaccel = { .name = "mpeg1_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG1VIDEO, @@ -1002,12 +1090,13 @@ AVHWAccel ff_mpeg1_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_mpeg2_videotoolbox_hwaccel = { +const AVHWAccel ff_mpeg2_videotoolbox_hwaccel = { .name = "mpeg2_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -1016,12 +1105,13 @@ AVHWAccel ff_mpeg2_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { +const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { .name = "mpeg4_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG4, @@ -1030,6 +1120,7 @@ AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), @@ -1057,13 +1148,13 @@ int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext * avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context(); if (!avctx->hwaccel_context) return AVERROR(ENOMEM); - return videotoolbox_default_init(avctx); + return videotoolbox_start(avctx); } void av_videotoolbox_default_free(AVCodecContext *avctx) { - videotoolbox_default_free(avctx); + videotoolbox_stop(avctx); av_freep(&avctx->hwaccel_context); } #endif /* CONFIG_VIDEOTOOLBOX */ diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index eba6cc672..7796a685c 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -35,6 +35,17 @@ #include "h264_sei.h" #include +#if !HAVE_KCMVIDEOCODECTYPE_HEVC +enum { kCMVideoCodecType_HEVC = 'hvc1' }; +#endif + +typedef OSStatus (*getParameterSetAtIndex)(CMFormatDescriptionRef videoDesc, + size_t parameterSetIndex, + const uint8_t * _Nullable *parameterSetPointerOut, + size_t *parameterSetSizeOut, + size_t *parameterSetCountOut, + int *NALUnitHeaderLengthOut); + //These symbols may not be present static struct{ CFStringRef kCVImageBufferColorPrimaries_ITU_R_2020; @@ -65,10 +76,15 @@ static struct{ CFStringRef kVTProfileLevel_H264_High_5_2; CFStringRef kVTProfileLevel_H264_High_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel; + CFStringRef kVTCompressionPropertyKey_RealTime; CFStringRef kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder; CFStringRef kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder; + + getParameterSetAtIndex CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; } compat_keys; #define GET_SYM(symbol, defaultVal) \ @@ -83,6 +99,12 @@ do{ \ static pthread_once_t once_ctrl = PTHREAD_ONCE_INIT; static void loadVTEncSymbols(){ + compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex = + (getParameterSetAtIndex)dlsym( + RTLD_DEFAULT, + "CMVideoFormatDescriptionGetHEVCParameterSetAtIndex" + ); + GET_SYM(kCVImageBufferColorPrimaries_ITU_R_2020, "ITU_R_2020"); GET_SYM(kCVImageBufferTransferFunction_ITU_R_2020, "ITU_R_2020"); GET_SYM(kCVImageBufferYCbCrMatrix_ITU_R_2020, "ITU_R_2020"); @@ -111,6 +133,9 @@ static void loadVTEncSymbols(){ GET_SYM(kVTProfileLevel_H264_High_5_2, "H264_High_5_2"); GET_SYM(kVTProfileLevel_H264_High_AutoLevel, "H264_High_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, "HEVC_Main_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, "HEVC_Main10_AutoLevel"); + GET_SYM(kVTCompressionPropertyKey_RealTime, "RealTime"); GET_SYM(kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, @@ -133,6 +158,13 @@ typedef enum VTH264Entropy{ VT_CABAC } VTH264Entropy; +typedef enum VT_HEVCProfile { + HEVC_PROF_AUTO, + HEVC_PROF_MAIN, + HEVC_PROF_MAIN10, + HEVC_PROF_COUNT +} VT_HEVCProfile; + static const uint8_t start_code[] = { 0, 0, 0, 1 }; typedef struct ExtraSEI { @@ -149,10 +181,12 @@ typedef struct BufNode { typedef struct VTEncContext { AVClass *class; + enum AVCodecID codec_id; VTCompressionSessionRef session; CFStringRef ycbcr_matrix; CFStringRef color_primaries; CFStringRef transfer_function; + getParameterSetAtIndex get_param_set_func; pthread_mutex_t lock; pthread_cond_t cv_sample_sent; @@ -348,6 +382,7 @@ static CMVideoCodecType get_cm_codec_type(enum AVCodecID id) { switch (id) { case AV_CODEC_ID_H264: return kCMVideoCodecType_H264; + case AV_CODEC_ID_HEVC: return kCMVideoCodecType_HEVC; default: return 0; } } @@ -365,17 +400,18 @@ static int get_params_size( CMVideoFormatDescriptionRef vid_fmt, size_t *size) { + VTEncContext *vtctx = avctx->priv_data; size_t total_size = 0; size_t ps_count; int is_count_bad = 0; size_t i; int status; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - 0, - NULL, - NULL, - &ps_count, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + 0, + NULL, + NULL, + &ps_count, + NULL); if (status) { is_count_bad = 1; ps_count = 0; @@ -385,12 +421,12 @@ static int get_params_size( for (i = 0; i < ps_count || is_count_bad; i++) { const uint8_t *ps; size_t ps_size; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - i, - &ps, - &ps_size, - NULL, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + i, + &ps, + &ps_size, + NULL, + NULL); if (status) { /* * When ps_count is invalid, status != 0 ends the loop normally @@ -419,18 +455,19 @@ static int copy_param_sets( uint8_t *dst, size_t dst_size) { + VTEncContext *vtctx = avctx->priv_data; size_t ps_count; int is_count_bad = 0; int status; size_t offset = 0; size_t i; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - 0, - NULL, - NULL, - &ps_count, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + 0, + NULL, + NULL, + &ps_count, + NULL); if (status) { is_count_bad = 1; ps_count = 0; @@ -443,12 +480,12 @@ static int copy_param_sets( size_t ps_size; size_t next_offset; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - i, - &ps, - &ps_size, - NULL, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + i, + &ps, + &ps_size, + NULL, + NULL); if (status) { if (i > 0 && is_count_bad) status = 0; @@ -548,6 +585,7 @@ static int get_length_code_size( CMSampleBufferRef sample_buffer, size_t *size) { + VTEncContext *vtctx = avctx->priv_data; CMVideoFormatDescriptionRef vid_fmt; int isize; int status; @@ -558,12 +596,12 @@ static int get_length_code_size( return AVERROR_EXTERNAL; } - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - 0, - NULL, - NULL, - NULL, - &isize); + status = vtctx->get_param_set_func(vid_fmt, + 0, + NULL, + NULL, + NULL, + &isize); if (status) { av_log(avctx, AV_LOG_ERROR, "Error getting length code size: %d\n", status); return AVERROR_EXTERNAL; @@ -579,8 +617,8 @@ static int get_length_code_size( * If profile_level_val is NULL and this method returns true, don't specify the * profile/level to the encoder. */ -static bool get_vt_profile_level(AVCodecContext *avctx, - CFStringRef *profile_level_val) +static bool get_vt_h264_profile_level(AVCodecContext *avctx, + CFStringRef *profile_level_val) { VTEncContext *vtctx = avctx->priv_data; int64_t profile = vtctx->profile; @@ -670,6 +708,41 @@ static bool get_vt_profile_level(AVCodecContext *avctx, return true; } +/* + * Returns true on success. + * + * If profile_level_val is NULL and this method returns true, don't specify the + * profile/level to the encoder. + */ +static bool get_vt_hevc_profile_level(AVCodecContext *avctx, + CFStringRef *profile_level_val) +{ + VTEncContext *vtctx = avctx->priv_data; + int64_t profile = vtctx->profile; + + *profile_level_val = NULL; + + switch (profile) { + case HEVC_PROF_AUTO: + return true; + case HEVC_PROF_MAIN: + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main_AutoLevel; + break; + case HEVC_PROF_MAIN10: + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel; + break; + } + + if (!*profile_level_val) { + av_log(avctx, AV_LOG_ERROR, "Invalid Profile/Level.\n"); + return false; + } + + return true; +} + static int get_cv_pixel_format(AVCodecContext* avctx, enum AVPixelFormat fmt, enum AVColorRange range, @@ -944,52 +1017,55 @@ static int vtenc_create_encoder(AVCodecContext *avctx, return AVERROR_EXTERNAL; } - bytes_per_second_value = max_rate >> 3; - bytes_per_second = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt64Type, - &bytes_per_second_value); - if (!bytes_per_second) { - return AVERROR(ENOMEM); - } - one_second_value = 1; - one_second = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt64Type, - &one_second_value); - if (!one_second) { - CFRelease(bytes_per_second); - return AVERROR(ENOMEM); - } - nums[0] = bytes_per_second; - nums[1] = one_second; - data_rate_limits = CFArrayCreate(kCFAllocatorDefault, - nums, - 2, - &kCFTypeArrayCallBacks); + if (vtctx->codec_id == AV_CODEC_ID_H264) { + // kVTCompressionPropertyKey_DataRateLimits is not available for HEVC + bytes_per_second_value = max_rate >> 3; + bytes_per_second = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt64Type, + &bytes_per_second_value); + if (!bytes_per_second) { + return AVERROR(ENOMEM); + } + one_second_value = 1; + one_second = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt64Type, + &one_second_value); + if (!one_second) { + CFRelease(bytes_per_second); + return AVERROR(ENOMEM); + } + nums[0] = (void *)bytes_per_second; + nums[1] = (void *)one_second; + data_rate_limits = CFArrayCreate(kCFAllocatorDefault, + (const void **)nums, + 2, + &kCFTypeArrayCallBacks); + + if (!data_rate_limits) { + CFRelease(bytes_per_second); + CFRelease(one_second); + return AVERROR(ENOMEM); + } + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_DataRateLimits, + data_rate_limits); - if (!data_rate_limits) { CFRelease(bytes_per_second); CFRelease(one_second); - return AVERROR(ENOMEM); - } - status = VTSessionSetProperty(vtctx->session, - kVTCompressionPropertyKey_DataRateLimits, - data_rate_limits); + CFRelease(data_rate_limits); - CFRelease(bytes_per_second); - CFRelease(one_second); - CFRelease(data_rate_limits); - - if (status) { - av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status); - return AVERROR_EXTERNAL; - } - - if (profile_level) { - status = VTSessionSetProperty(vtctx->session, - kVTCompressionPropertyKey_ProfileLevel, - profile_level); if (status) { - av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status); + av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status); + return AVERROR_EXTERNAL; + } + + if (profile_level) { + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_ProfileLevel, + profile_level); + if (status) { + av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status); + } } } @@ -1205,18 +1281,28 @@ static av_cold int vtenc_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - vtctx->has_b_frames = avctx->max_b_frames > 0; - if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){ - av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n"); - vtctx->has_b_frames = false; - } + vtctx->codec_id = avctx->codec_id; - if (vtctx->entropy == VT_CABAC && vtctx->profile == H264_PROF_BASELINE) { - av_log(avctx, AV_LOG_WARNING, "CABAC entropy requires 'main' or 'high' profile, but baseline was requested. Encode will not use CABAC entropy.\n"); - vtctx->entropy = VT_ENTROPY_NOT_SET; - } + if (vtctx->codec_id == AV_CODEC_ID_H264) { + vtctx->get_param_set_func = CMVideoFormatDescriptionGetH264ParameterSetAtIndex; - if (!get_vt_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + vtctx->has_b_frames = avctx->max_b_frames > 0; + if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){ + av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n"); + vtctx->has_b_frames = false; + } + + if (vtctx->entropy == VT_CABAC && vtctx->profile == H264_PROF_BASELINE) { + av_log(avctx, AV_LOG_WARNING, "CABAC entropy requires 'main' or 'high' profile, but baseline was requested. Encode will not use CABAC entropy.\n"); + vtctx->entropy = VT_ENTROPY_NOT_SET; + } + + if (!get_vt_h264_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + } else { + vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; + if (!vtctx->get_param_set_func) return AVERROR(EINVAL); + if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + } vtctx->session = NULL; @@ -1853,8 +1939,6 @@ static int get_cv_pixel_info( "Color range not set for %s. Using MPEG range.\n", av_get_pix_fmt_name(av_format)); } - - av_log(avctx, AV_LOG_WARNING, ""); } switch (av_format) { @@ -2424,9 +2508,19 @@ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NONE }; -#define OFFSET(x) offsetof(VTEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -static const AVOption options[] = { +#define COMMON_OPTIONS \ + { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \ + { .i64 = 0 }, 0, 1, VE }, \ + { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", \ + OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ + { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", \ + OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ + { "frames_after", "Other frames will come after the frames in this session. This helps smooth concatenation issues.", \ + OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + +#define OFFSET(x) offsetof(VTEncContext, x) +static const AVOption h264_options[] = { { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = H264_PROF_AUTO }, H264_PROF_AUTO, H264_PROF_COUNT, VE, "profile" }, { "baseline", "Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROF_BASELINE }, INT_MIN, INT_MAX, VE, "profile" }, { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, @@ -2444,32 +2538,22 @@ static const AVOption options[] = { { "5.1", "Level 5.1", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, INT_MIN, INT_MAX, VE, "level" }, { "5.2", "Level 5.2", 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, INT_MIN, INT_MAX, VE, "level" }, - { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, - { .i64 = 0 }, 0, 1, VE }, - { "coder", "Entropy coding", OFFSET(entropy), AV_OPT_TYPE_INT, { .i64 = VT_ENTROPY_NOT_SET }, VT_ENTROPY_NOT_SET, VT_CABAC, VE, "coder" }, { "cavlc", "CAVLC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CAVLC }, INT_MIN, INT_MAX, VE, "coder" }, { "vlc", "CAVLC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CAVLC }, INT_MIN, INT_MAX, VE, "coder" }, { "cabac", "CABAC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CABAC }, INT_MIN, INT_MAX, VE, "coder" }, { "ac", "CABAC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CABAC }, INT_MIN, INT_MAX, VE, "coder" }, - { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", - OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - - { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", - OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "frames_after", "Other frames will come after the frames in this session. This helps smooth concatenation issues.", - OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, VE }, + COMMON_OPTIONS { NULL }, }; static const AVClass h264_videotoolbox_class = { .class_name = "h264_videotoolbox", .item_name = av_default_item_name, - .option = options, + .option = h264_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -2488,3 +2572,36 @@ AVCodec ff_h264_videotoolbox_encoder = { .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; + +static const AVOption hevc_options[] = { + { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = HEVC_PROF_AUTO }, HEVC_PROF_AUTO, HEVC_PROF_COUNT, VE, "profile" }, + { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = HEVC_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, + { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = HEVC_PROF_MAIN10 }, INT_MIN, INT_MAX, VE, "profile" }, + + COMMON_OPTIONS + { NULL }, +}; + +static const AVClass hevc_videotoolbox_class = { + .class_name = "hevc_videotoolbox", + .item_name = av_default_item_name, + .option = hevc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_hevc_videotoolbox_encoder = { + .name = "hevc_videotoolbox", + .long_name = NULL_IF_CONFIG_SMALL("VideoToolbox H.265 Encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .priv_data_size = sizeof(VTEncContext), + .pix_fmts = pix_fmts, + .init = vtenc_init, + .encode2 = vtenc_frame, + .close = vtenc_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, + .priv_class = &hevc_videotoolbox_class, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "videotoolbox", +}; diff --git a/libavcodec/vorbis.c b/libavcodec/vorbis.c index 399020eec..cca2aa7c6 100644 --- a/libavcodec/vorbis.c +++ b/libavcodec/vorbis.c @@ -58,7 +58,7 @@ 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; (bits[p] == 0) && (p < num); ++p) + for (p = 0; (p < num) && (bits[p] == 0); ++p) ; if (p == num) return 0; @@ -67,11 +67,11 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) if (bits[p] > 32) return AVERROR_INVALIDDATA; for (i = 0; i < bits[p]; ++i) - exit_at_level[i+1] = 1 << i; + exit_at_level[i+1] = 1u << i; ++p; - for (i = p; (bits[i] == 0) && (i < num); ++i) + for (i = p; (i < num) && (bits[i] == 0); ++i) ; if (i == num) return 0; @@ -91,7 +91,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) 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 + (1 << (j - 1)); + exit_at_level[j] = code + (1u << (j - 1)); codes[p] = code; } diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c index a4ecd8f75..18a679f2d 100644 --- a/libavcodec/vorbisenc.c +++ b/libavcodec/vorbisenc.c @@ -1093,9 +1093,13 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, PutBitContext pb; if (frame) { + AVFrame *clone; if ((ret = ff_af_queue_add(&venc->afq, frame)) < 0) return ret; - ff_bufqueue_add(avctx, &venc->bufqueue, av_frame_clone(frame)); + clone = av_frame_clone(frame); + if (!clone) + return AVERROR(ENOMEM); + ff_bufqueue_add(avctx, &venc->bufqueue, clone); } else if (!venc->afq.remaining_samples) return 0; diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index f167acf4e..cf9c57f5f 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -1761,7 +1761,9 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) for (i = 0; i < 3; i++) s->qps[i] = -1; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + if (ret) + return ret; s->y_superblock_width = (s->width + 31) / 32; s->y_superblock_height = (s->height + 31) / 32; diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index 7841a9d96..7f71a75e4 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -27,6 +27,7 @@ #include "libavutil/imgutils.h" #include "avcodec.h" +#include "hwaccel.h" #include "internal.h" #include "mathops.h" #include "rectangle.h" @@ -72,16 +73,30 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) if ((ret = ff_thread_get_buffer(s->avctx, &f->tf, ref ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) return ret; - if (!(f->seg_map = av_buffer_allocz(s->mb_width * s->mb_height))) { - ff_thread_release_buffer(s->avctx, &f->tf); - return AVERROR(ENOMEM); + if (!(f->seg_map = av_buffer_allocz(s->mb_width * s->mb_height))) + goto fail; + if (s->avctx->hwaccel) { + const AVHWAccel *hwaccel = s->avctx->hwaccel; + if (hwaccel->frame_priv_data_size) { + f->hwaccel_priv_buf = av_buffer_allocz(hwaccel->frame_priv_data_size); + if (!f->hwaccel_priv_buf) + goto fail; + f->hwaccel_picture_private = f->hwaccel_priv_buf->data; + } } return 0; + +fail: + av_buffer_unref(&f->seg_map); + ff_thread_release_buffer(s->avctx, &f->tf); + return AVERROR(ENOMEM); } static void vp8_release_frame(VP8Context *s, VP8Frame *f) { av_buffer_unref(&f->seg_map); + av_buffer_unref(&f->hwaccel_priv_buf); + f->hwaccel_picture_private = NULL; ff_thread_release_buffer(s->avctx, &f->tf); } @@ -99,6 +114,12 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, VP8Frame *src) vp8_release_frame(s, dst); return AVERROR(ENOMEM); } + if (src->hwaccel_picture_private) { + dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); + if (!dst->hwaccel_priv_buf) + return AVERROR(ENOMEM); + dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; + } return 0; } @@ -140,12 +161,28 @@ static VP8Frame *vp8_find_free_buffer(VP8Context *s) av_log(s->avctx, AV_LOG_FATAL, "Ran out of free frames!\n"); abort(); } - if (frame->tf.f->data[0]) + if (frame->tf.f->buf[0]) vp8_release_frame(s, frame); return frame; } +static enum AVPixelFormat get_pixel_format(VP8Context *s) +{ + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_VP8_VAAPI_HWACCEL + AV_PIX_FMT_VAAPI, +#endif +#if CONFIG_VP8_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE, + }; + + return ff_get_format(s->avctx, pix_fmts); +} + static av_always_inline int update_dimensions(VP8Context *s, int width, int height, int is_vp7) { @@ -161,6 +198,13 @@ int update_dimensions(VP8Context *s, int width, int height, int is_vp7) return ret; } + if (!s->actually_webp && !is_vp7) { + s->pix_fmt = get_pixel_format(s); + if (s->pix_fmt < 0) + return AVERROR(EINVAL); + avctx->pix_fmt = s->pix_fmt; + } + s->mb_width = (s->avctx->coded_width + 15) / 16; s->mb_height = (s->avctx->coded_height + 15) / 16; @@ -218,8 +262,9 @@ static void parse_segment_info(VP8Context *s) int i; s->segmentation.update_map = vp8_rac_get(c); + s->segmentation.update_feature_data = vp8_rac_get(c); - if (vp8_rac_get(c)) { // update segment feature data + if (s->segmentation.update_feature_data) { s->segmentation.absolute_vals = vp8_rac_get(c); for (i = 0; i < 4; i++) @@ -274,6 +319,7 @@ static int setup_partitions(VP8Context *s, const uint8_t *buf, int buf_size) int size = AV_RL24(sizes + 3 * i); if (buf_size - size < 0) return -1; + s->coeff_partition_size[i] = size; ret = ff_vp56_init_range_decoder(&s->coeff_partition[i], buf, size); if (ret < 0) @@ -281,7 +327,11 @@ static int setup_partitions(VP8Context *s, const uint8_t *buf, int buf_size) buf += size; buf_size -= size; } - return ff_vp56_init_range_decoder(&s->coeff_partition[i], buf, buf_size); + + s->coeff_partition_size[i] = buf_size; + ff_vp56_init_range_decoder(&s->coeff_partition[i], buf, buf_size); + + return 0; } static void vp7_get_quants(VP8Context *s) @@ -308,28 +358,28 @@ static void vp8_get_quants(VP8Context *s) VP56RangeCoder *c = &s->c; int i, base_qi; - int yac_qi = vp8_rac_get_uint(c, 7); - int ydc_delta = vp8_rac_get_sint(c, 4); - int y2dc_delta = vp8_rac_get_sint(c, 4); - int y2ac_delta = vp8_rac_get_sint(c, 4); - int uvdc_delta = vp8_rac_get_sint(c, 4); - int uvac_delta = vp8_rac_get_sint(c, 4); + s->quant.yac_qi = vp8_rac_get_uint(c, 7); + s->quant.ydc_delta = vp8_rac_get_sint(c, 4); + s->quant.y2dc_delta = vp8_rac_get_sint(c, 4); + s->quant.y2ac_delta = vp8_rac_get_sint(c, 4); + s->quant.uvdc_delta = vp8_rac_get_sint(c, 4); + s->quant.uvac_delta = vp8_rac_get_sint(c, 4); for (i = 0; i < 4; i++) { if (s->segmentation.enabled) { base_qi = s->segmentation.base_quant[i]; if (!s->segmentation.absolute_vals) - base_qi += yac_qi; + base_qi += s->quant.yac_qi; } else - base_qi = yac_qi; + base_qi = s->quant.yac_qi; - s->qmat[i].luma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + ydc_delta, 7)]; + s->qmat[i].luma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + s->quant.ydc_delta, 7)]; s->qmat[i].luma_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi, 7)]; - s->qmat[i].luma_dc_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + y2dc_delta, 7)] * 2; + s->qmat[i].luma_dc_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7)] * 2; /* 101581>>16 is equivalent to 155/100 */ - s->qmat[i].luma_dc_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + y2ac_delta, 7)] * 101581 >> 16; - s->qmat[i].chroma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + uvdc_delta, 7)]; - s->qmat[i].chroma_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + uvac_delta, 7)]; + s->qmat[i].luma_dc_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7)] * 101581 >> 16; + s->qmat[i].chroma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7)]; + s->qmat[i].chroma_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + s->quant.uvac_delta, 7)]; s->qmat[i].luma_dc_qmul[1] = FFMAX(s->qmat[i].luma_dc_qmul[1], 8); s->qmat[i].chroma_qmul[0] = FFMIN(s->qmat[i].chroma_qmul[0], 132); @@ -661,6 +711,8 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si buf += 3; buf_size -= 3; + s->header_partition_size = header_size; + if (s->profile > 3) av_log(s->avctx, AV_LOG_WARNING, "Unknown profile %d\n", s->profile); @@ -726,9 +778,11 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si s->filter.level = vp8_rac_get_uint(c, 6); s->filter.sharpness = vp8_rac_get_uint(c, 3); - if ((s->lf_delta.enabled = vp8_rac_get(c))) - if (vp8_rac_get(c)) + if ((s->lf_delta.enabled = vp8_rac_get(c))) { + s->lf_delta.update = vp8_rac_get(c); + if (s->lf_delta.update) update_lf_deltas(s); + } if (setup_partitions(s, buf, buf_size)) { av_log(s->avctx, AV_LOG_ERROR, "Invalid partitions\n"); @@ -768,6 +822,13 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si vp78_update_pred16x16_pred8x8_mvc_probabilities(s, VP8_MVC_SIZE); } + // Record the entropy coder state here so that hwaccels can use it. + s->c.code_word = vp56_rac_renorm(&s->c); + s->coder_state_at_header_end.input = s->c.buffer - (-s->c.bits / 8); + s->coder_state_at_header_end.range = s->c.high; + s->coder_state_at_header_end.value = s->c.code_word >> 16; + s->coder_state_at_header_end.bit_count = -s->c.bits % 8; + return 0; } @@ -2540,7 +2601,6 @@ static int vp8_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, return vp78_decode_mb_row_sliced(avctx, tdata, jobnr, threadnr, IS_VP8); } - static av_always_inline int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt, int is_vp7) @@ -2550,8 +2610,6 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, enum AVDiscard skip_thresh; VP8Frame *av_uninit(curframe), *prev_frame; - av_assert0(avctx->pix_fmt == AV_PIX_FMT_YUVA420P || avctx->pix_fmt == AV_PIX_FMT_YUV420P); - if (is_vp7) ret = vp7_decode_frame_header(s, avpkt->data, avpkt->size); else @@ -2560,6 +2618,17 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (ret < 0) goto err; + if (s->actually_webp) { + // avctx->pix_fmt already set in caller. + } else if (!is_vp7 && s->pix_fmt == AV_PIX_FMT_NONE) { + s->pix_fmt = get_pixel_format(s); + if (s->pix_fmt < 0) { + ret = AVERROR(EINVAL); + goto err; + } + avctx->pix_fmt = s->pix_fmt; + } + prev_frame = s->framep[VP56_FRAME_CURRENT]; referenced = s->update_last || s->update_golden == VP56_FRAME_CURRENT || @@ -2578,7 +2647,7 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, // release no longer referenced frames for (i = 0; i < 5; i++) - if (s->frames[i].tf.f->data[0] && + if (s->frames[i].tf.f->buf[0] && &s->frames[i] != prev_frame && &s->frames[i] != s->framep[VP56_FRAME_PREVIOUS] && &s->frames[i] != s->framep[VP56_FRAME_GOLDEN] && @@ -2631,56 +2700,70 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->next_framep[VP56_FRAME_CURRENT] = curframe; - if (avctx->codec->update_thread_context) - ff_thread_finish_setup(avctx); + ff_thread_finish_setup(avctx); - s->linesize = curframe->tf.f->linesize[0]; - s->uvlinesize = curframe->tf.f->linesize[1]; + if (avctx->hwaccel) { + ret = avctx->hwaccel->start_frame(avctx, avpkt->data, avpkt->size); + if (ret < 0) + goto err; - memset(s->top_nnz, 0, s->mb_width * sizeof(*s->top_nnz)); - /* Zero macroblock structures for top/top-left prediction - * from outside the frame. */ - if (!s->mb_layout) - memset(s->macroblocks + s->mb_height * 2 - 1, 0, - (s->mb_width + 1) * sizeof(*s->macroblocks)); - if (!s->mb_layout && s->keyframe) - memset(s->intra4x4_pred_mode_top, DC_PRED, s->mb_width * 4); + ret = avctx->hwaccel->decode_slice(avctx, avpkt->data, avpkt->size); + if (ret < 0) + goto err; - memset(s->ref_count, 0, sizeof(s->ref_count)); + ret = avctx->hwaccel->end_frame(avctx); + if (ret < 0) + goto err; - if (s->mb_layout == 1) { - // Make sure the previous frame has read its segmentation map, - // if we re-use the same map. - if (prev_frame && s->segmentation.enabled && - !s->segmentation.update_map) - ff_thread_await_progress(&prev_frame->tf, 1, 0); - if (is_vp7) - vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); + } else { + s->linesize = curframe->tf.f->linesize[0]; + s->uvlinesize = curframe->tf.f->linesize[1]; + + memset(s->top_nnz, 0, s->mb_width * sizeof(*s->top_nnz)); + /* Zero macroblock structures for top/top-left prediction + * from outside the frame. */ + if (!s->mb_layout) + memset(s->macroblocks + s->mb_height * 2 - 1, 0, + (s->mb_width + 1) * sizeof(*s->macroblocks)); + if (!s->mb_layout && s->keyframe) + memset(s->intra4x4_pred_mode_top, DC_PRED, s->mb_width * 4); + + memset(s->ref_count, 0, sizeof(s->ref_count)); + + if (s->mb_layout == 1) { + // Make sure the previous frame has read its segmentation map, + // if we re-use the same map. + if (prev_frame && s->segmentation.enabled && + !s->segmentation.update_map) + ff_thread_await_progress(&prev_frame->tf, 1, 0); + if (is_vp7) + vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); + else + vp8_decode_mv_mb_modes(avctx, curframe, prev_frame); + } + + if (avctx->active_thread_type == FF_THREAD_FRAME) + num_jobs = 1; else - vp8_decode_mv_mb_modes(avctx, curframe, prev_frame); + num_jobs = FFMIN(s->num_coeff_partitions, avctx->thread_count); + s->num_jobs = num_jobs; + s->curframe = curframe; + s->prev_frame = prev_frame; + s->mv_bounds.mv_min.y = -MARGIN; + s->mv_bounds.mv_max.y = ((s->mb_height - 1) << 6) + MARGIN; + for (i = 0; i < MAX_THREADS; i++) { + VP8ThreadData *td = &s->thread_data[i]; + atomic_init(&td->thread_mb_pos, 0); + atomic_init(&td->wait_mb_pos, INT_MAX); + } + if (is_vp7) + avctx->execute2(avctx, vp7_decode_mb_row_sliced, s->thread_data, NULL, + num_jobs); + else + avctx->execute2(avctx, vp8_decode_mb_row_sliced, s->thread_data, NULL, + num_jobs); } - if (avctx->active_thread_type == FF_THREAD_FRAME) - num_jobs = 1; - else - num_jobs = FFMIN(s->num_coeff_partitions, avctx->thread_count); - s->num_jobs = num_jobs; - s->curframe = curframe; - s->prev_frame = prev_frame; - s->mv_bounds.mv_min.y = -MARGIN; - s->mv_bounds.mv_max.y = ((s->mb_height - 1) << 6) + MARGIN; - for (i = 0; i < MAX_THREADS; i++) { - VP8ThreadData *td = &s->thread_data[i]; - atomic_init(&td->thread_mb_pos, 0); - atomic_init(&td->wait_mb_pos, INT_MAX); - } - if (is_vp7) - avctx->execute2(avctx, vp7_decode_mb_row_sliced, s->thread_data, NULL, - num_jobs); - else - avctx->execute2(avctx, vp8_decode_mb_row_sliced, s->thread_data, NULL, - num_jobs); - ff_thread_report_progress(&curframe->tf, INT_MAX, 0); memcpy(&s->framep[0], &s->next_framep[0], sizeof(s->framep[0]) * 4); @@ -2750,6 +2833,7 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7) s->avctx = avctx; s->vp7 = avctx->codec->id == AV_CODEC_ID_VP7; + s->pix_fmt = AV_PIX_FMT_NONE; avctx->pix_fmt = AV_PIX_FMT_YUV420P; avctx->internal->allocate_progress = 1; @@ -2823,13 +2907,14 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, s->mb_height = s_src->mb_height; } + s->pix_fmt = s_src->pix_fmt; s->prob[0] = s_src->prob[!s_src->update_probabilities]; s->segmentation = s_src->segmentation; s->lf_delta = s_src->lf_delta; memcpy(s->sign_bias, s_src->sign_bias, sizeof(s->sign_bias)); for (i = 0; i < FF_ARRAY_ELEMS(s_src->frames); i++) { - if (s_src->frames[i].tf.f->data[0]) { + if (s_src->frames[i].tf.f->buf[0]) { int ret = vp8_ref_frame(s, &s->frames[i], &s_src->frames[i]); if (ret < 0) return ret; @@ -2876,5 +2961,14 @@ AVCodec ff_vp8_decoder = { .flush = vp8_decode_flush, .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp8_decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(vp8_decode_update_thread_context), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_VP8_VAAPI_HWACCEL + HWACCEL_VAAPI(vp8), +#endif +#if CONFIG_VP8_NVDEC_HWACCEL + HWACCEL_NVDEC(vp8), +#endif + NULL + }, }; #endif /* CONFIG_VP7_DECODER */ diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h index 8263997e3..70d21e3c6 100644 --- a/libavcodec/vp8.h +++ b/libavcodec/vp8.h @@ -138,12 +138,18 @@ typedef struct VP8ThreadData { typedef struct VP8Frame { ThreadFrame tf; AVBufferRef *seg_map; + + AVBufferRef *hwaccel_priv_buf; + void *hwaccel_picture_private; } VP8Frame; #define MAX_THREADS 8 typedef struct VP8Context { VP8ThreadData *thread_data; AVCodecContext *avctx; + enum AVPixelFormat pix_fmt; + int actually_webp; + VP8Frame *framep[4]; VP8Frame *next_framep[4]; VP8Frame *curframe; @@ -172,6 +178,7 @@ typedef struct VP8Context { uint8_t enabled; uint8_t absolute_vals; uint8_t update_map; + uint8_t update_feature_data; int8_t base_quant[4]; int8_t filter_level[4]; ///< base loop filter level } segmentation; @@ -199,8 +206,19 @@ typedef struct VP8Context { int16_t chroma_qmul[2]; } qmat[4]; + // Raw quantisation values, which may be needed by hwaccel decode. + struct { + int yac_qi; + int ydc_delta; + int y2dc_delta; + int y2ac_delta; + int uvdc_delta; + int uvac_delta; + } quant; + struct { uint8_t enabled; ///< whether each mb can have a different strength based on mode/ref + uint8_t update; /** * filter strength adjustment for the following macroblock modes: @@ -228,6 +246,20 @@ typedef struct VP8Context { VP56RangeCoder c; ///< header context, includes mb modes and motion vectors + /* This contains the entropy coder state at the end of the header + * block, in the form specified by the standard. For use by + * hwaccels, so that a hardware decoder has the information to + * start decoding at the macroblock layer. + */ + struct { + const uint8_t *input; + uint32_t range; + uint32_t value; + int bit_count; + } coder_state_at_header_end; + + int header_partition_size; + /** * These are all of the updatable probabilities for binary decisions. * They are only implicitly reset on keyframes, making it quite likely @@ -265,6 +297,7 @@ typedef struct VP8Context { */ int num_coeff_partitions; VP56RangeCoder coeff_partition[8]; + int coeff_partition_size[8]; VideoDSPContext vdsp; VP8DSPContext vp8dsp; H264PredContext hpc; diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index 6b5de1926..0fac638ec 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -23,6 +23,7 @@ #include "avcodec.h" #include "get_bits.h" +#include "hwaccel.h" #include "internal.h" #include "profiles.h" #include "thread.h" @@ -169,7 +170,10 @@ fail: static int update_size(AVCodecContext *avctx, int w, int h) { -#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + CONFIG_VP9_D3D11VA_HWACCEL * 2 + CONFIG_VP9_VAAPI_HWACCEL) +#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + \ + CONFIG_VP9_D3D11VA_HWACCEL * 2 + \ + CONFIG_VP9_NVDEC_HWACCEL + \ + CONFIG_VP9_VAAPI_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; VP9Context *s = avctx->priv_data; uint8_t *p; @@ -191,12 +195,18 @@ static int update_size(AVCodecContext *avctx, int w, int h) *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; *fmtp++ = AV_PIX_FMT_D3D11; #endif +#if CONFIG_VP9_NVDEC_HWACCEL + *fmtp++ = AV_PIX_FMT_CUDA; +#endif #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; #endif break; case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV420P12: +#if CONFIG_VP9_NVDEC_HWACCEL + *fmtp++ = AV_PIX_FMT_CUDA; +#endif #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; #endif @@ -1634,8 +1644,10 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif { ret = decode_tiles(avctx, data, size); - if (ret < 0) + if (ret < 0) { + ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0); return ret; + } } // Sum all counts fields into td[0].counts for tile threading @@ -1785,4 +1797,23 @@ AVCodec ff_vp9_decoder = { .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp9_decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(vp9_decode_update_thread_context), .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), + .bsfs = "vp9_superframe_split", + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_VP9_DXVA2_HWACCEL + HWACCEL_DXVA2(vp9), +#endif +#if CONFIG_VP9_D3D11VA_HWACCEL + HWACCEL_D3D11VA(vp9), +#endif +#if CONFIG_VP9_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(vp9), +#endif +#if CONFIG_VP9_NVDEC_HWACCEL + HWACCEL_NVDEC(vp9), +#endif +#if CONFIG_VP9_VAAPI_HWACCEL + HWACCEL_VAAPI(vp9), +#endif + NULL + }, }; diff --git a/libavcodec/vp9_parser.c b/libavcodec/vp9_parser.c index 9900e7ab1..9531f34a3 100644 --- a/libavcodec/vp9_parser.c +++ b/libavcodec/vp9_parser.c @@ -25,21 +25,19 @@ #include "libavcodec/get_bits.h" #include "parser.h" -typedef struct VP9ParseContext { - int n_frames; // 1-8 - int size[8]; - int marker_size; - int64_t pts; -} VP9ParseContext; - -static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) +static int parse(AVCodecParserContext *ctx, + AVCodecContext *avctx, + const uint8_t **out_data, int *out_size, + const uint8_t *data, int size) { - VP9ParseContext *s = ctx->priv_data; GetBitContext gb; - int res, profile, keyframe, invisible; + int res, profile, keyframe; - if ((res = init_get_bits8(&gb, buf, size)) < 0) - return res; + *out_data = data; + *out_size = size; + + if ((res = init_get_bits8(&gb, data, size)) < 0) + return size; // parsers can't return errors get_bits(&gb, 2); // frame marker profile = get_bits1(&gb); profile |= get_bits1(&gb) << 1; @@ -47,10 +45,8 @@ static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) if (get_bits1(&gb)) { keyframe = 0; - invisible = 0; } else { keyframe = !get_bits1(&gb); - invisible = !get_bits1(&gb); } if (!keyframe) { @@ -61,113 +57,10 @@ static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) ctx->key_frame = 1; } - if (!invisible) { - if (ctx->pts == AV_NOPTS_VALUE) - ctx->pts = s->pts; - s->pts = AV_NOPTS_VALUE; - } else if (ctx->pts != AV_NOPTS_VALUE) { - s->pts = ctx->pts; - ctx->pts = AV_NOPTS_VALUE; - } - - return 0; -} - -static int parse(AVCodecParserContext *ctx, - AVCodecContext *avctx, - const uint8_t **out_data, int *out_size, - const uint8_t *data, int size) -{ - VP9ParseContext *s = ctx->priv_data; - int full_size = size; - int marker; - - if (size <= 0) { - *out_size = 0; - *out_data = data; - - return 0; - } - - if (s->n_frames > 0) { - int i; - int size_sum = 0; - - for (i = 0; i < s->n_frames ;i++) - size_sum += s->size[i]; - size_sum += s->marker_size; - - if (size_sum != size) { - av_log(avctx, AV_LOG_ERROR, "Inconsistent input frame sizes %d %d\n", - size_sum, size); - s->n_frames = 0; - } - } - - if (s->n_frames > 0) { - *out_data = data; - *out_size = s->size[--s->n_frames]; - parse_frame(ctx, *out_data, *out_size); - - return s->n_frames > 0 ? *out_size : size /* i.e. include idx tail */; - } - - marker = data[size - 1]; - if ((marker & 0xe0) == 0xc0) { - int nbytes = 1 + ((marker >> 3) & 0x3); - int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; - - if (size >= idx_sz && data[size - idx_sz] == marker) { - const uint8_t *idx = data + size + 1 - idx_sz; - int first = 1; - - switch (nbytes) { -#define case_n(a, rd) \ - case a: \ - while (n_frames--) { \ - unsigned sz = rd; \ - idx += a; \ - if (sz == 0 || sz > size) { \ - s->n_frames = 0; \ - *out_size = size; \ - *out_data = data; \ - av_log(avctx, AV_LOG_ERROR, \ - "Invalid superframe packet size: %u frame size: %d\n", \ - sz, size); \ - return full_size; \ - } \ - if (first) { \ - first = 0; \ - *out_data = data; \ - *out_size = sz; \ - s->n_frames = n_frames; \ - } else { \ - s->size[n_frames] = sz; \ - } \ - data += sz; \ - size -= sz; \ - } \ - s->marker_size = size; \ - parse_frame(ctx, *out_data, *out_size); \ - return s->n_frames > 0 ? *out_size : full_size - - case_n(1, *idx); - case_n(2, AV_RL16(idx)); - case_n(3, AV_RL24(idx)); - case_n(4, AV_RL32(idx)); - } - } - } - - *out_data = data; - *out_size = size; - parse_frame(ctx, data, size); - return size; } AVCodecParser ff_vp9_parser = { .codec_ids = { AV_CODEC_ID_VP9 }, - .priv_data_size = sizeof(VP9ParseContext), .parser_parse = parse, }; diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c index b686adbe1..2ea49c672 100644 --- a/libavcodec/vp9_superframe_bsf.c +++ b/libavcodec/vp9_superframe_bsf.c @@ -27,20 +27,17 @@ #define MAX_CACHE 8 typedef struct VP9BSFContext { int n_cache; - struct CachedBuf { - uint8_t *data; - int size; - } cache[MAX_CACHE]; + AVPacket *cache[MAX_CACHE]; } VP9BSFContext; -static void stats(const struct CachedBuf *in, int n_in, +static void stats(AVPacket * const *in, int n_in, unsigned *_max, unsigned *_sum) { int n; unsigned max = 0, sum = 0; for (n = 0; n < n_in; n++) { - unsigned sz = in[n].size; + unsigned sz = in[n]->size; if (sz > max) max = sz; @@ -51,7 +48,7 @@ static void stats(const struct CachedBuf *in, int n_in, *_sum = sum; } -static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) +static int merge_superframe(AVPacket * const *in, int n_in, AVPacket *out) { unsigned max, sum, mag, marker, n, sz; uint8_t *ptr; @@ -66,30 +63,32 @@ static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) return res; ptr = out->data; for (n = 0; n < n_in; n++) { - memcpy(ptr, in[n].data, in[n].size); - ptr += in[n].size; + memcpy(ptr, in[n]->data, in[n]->size); + ptr += in[n]->size; } #define wloop(mag, wr) \ - for (n = 0; n < n_in; n++) { \ - wr; \ - ptr += mag + 1; \ - } + do { \ + for (n = 0; n < n_in; n++) { \ + wr; \ + ptr += mag + 1; \ + } \ + } while (0) // write superframe with marker 110[mag:2][nframes:3] *ptr++ = marker; switch (mag) { case 0: - wloop(mag, *ptr = in[n].size); + wloop(mag, *ptr = in[n]->size); break; case 1: - wloop(mag, AV_WL16(ptr, in[n].size)); + wloop(mag, AV_WL16(ptr, in[n]->size)); break; case 2: - wloop(mag, AV_WL24(ptr, in[n].size)); + wloop(mag, AV_WL24(ptr, in[n]->size)); break; case 3: - wloop(mag, AV_WL32(ptr, in[n].size)); + wloop(mag, AV_WL32(ptr, in[n]->size)); break; } *ptr++ = marker; @@ -135,7 +134,7 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) if (uses_superframe_syntax && s->n_cache > 0) { av_log(ctx, AV_LOG_ERROR, "Mixing of superframe syntax and naked VP9 frames not supported"); - res = AVERROR_INVALIDDATA; + res = AVERROR(ENOSYS); goto done; } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { // passthrough @@ -148,33 +147,28 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) goto done; } - s->cache[s->n_cache].size = in->size; - if (invisible && !uses_superframe_syntax) { - s->cache[s->n_cache].data = av_malloc(in->size); - if (!s->cache[s->n_cache].data) { - res = AVERROR(ENOMEM); - goto done; - } - memcpy(s->cache[s->n_cache++].data, in->data, in->size); + res = av_packet_ref(s->cache[s->n_cache++], in); + if (res < 0) + goto done; + + if (invisible) { res = AVERROR(EAGAIN); goto done; } av_assert0(s->n_cache > 0); - s->cache[s->n_cache].data = in->data; - // build superframe - if ((res = merge_superframe(s->cache, s->n_cache + 1, out)) < 0) + if ((res = merge_superframe(s->cache, s->n_cache, out)) < 0) + goto done; + + res = av_packet_copy_props(out, s->cache[s->n_cache - 1]); + if (res < 0) goto done; for (n = 0; n < s->n_cache; n++) - av_freep(&s->cache[n].data); + av_packet_unref(s->cache[n]); s->n_cache = 0; - res = av_packet_copy_props(out, in); - if (res < 0) - goto done; - done: if (res < 0) av_packet_unref(out); @@ -182,14 +176,29 @@ done: return res; } +static int vp9_superframe_init(AVBSFContext *ctx) +{ + VP9BSFContext *s = ctx->priv_data; + int n; + + // alloc cache packets + for (n = 0; n < MAX_CACHE; n++) { + s->cache[n] = av_packet_alloc(); + if (!s->cache[n]) + return AVERROR(ENOMEM); + } + + return 0; +} + static void vp9_superframe_close(AVBSFContext *ctx) { VP9BSFContext *s = ctx->priv_data; int n; // free cached data - for (n = 0; n < s->n_cache; n++) - av_freep(&s->cache[n].data); + for (n = 0; n < MAX_CACHE; n++) + av_packet_free(&s->cache[n]); } static const enum AVCodecID codec_ids[] = { @@ -200,6 +209,7 @@ const AVBitStreamFilter ff_vp9_superframe_bsf = { .name = "vp9_superframe", .priv_data_size = sizeof(VP9BSFContext), .filter = vp9_superframe_filter, + .init = vp9_superframe_init, .close = vp9_superframe_close, .codec_ids = codec_ids, }; diff --git a/libavcodec/vp9_superframe_split_bsf.c b/libavcodec/vp9_superframe_split_bsf.c index 6d6d8e664..0d2523ebf 100644 --- a/libavcodec/vp9_superframe_split_bsf.c +++ b/libavcodec/vp9_superframe_split_bsf.c @@ -59,7 +59,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) if (in->size >= idx_size && in->data[in->size - idx_size] == marker) { GetByteContext bc; - int total_size = 0; + int64_t total_size = 0; bytestream2_init(&bc, in->data + in->size + 1 - idx_size, nb_frames * length_size); @@ -70,7 +70,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) frame_size |= bytestream2_get_byte(&bc) << (j * 8); total_size += frame_size; - if (total_size > in->size - idx_size) { + if (frame_size < 0 || total_size > in->size - idx_size) { av_log(ctx, AV_LOG_ERROR, "Invalid frame size in a superframe: %d\n", frame_size); ret = AVERROR(EINVAL); diff --git a/libavcodec/vda_vt_internal.h b/libavcodec/vt_internal.h similarity index 82% rename from libavcodec/vda_vt_internal.h rename to libavcodec/vt_internal.h index 326a60a69..929fe423f 100644 --- a/libavcodec/vda_vt_internal.h +++ b/libavcodec/vt_internal.h @@ -16,17 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VDA_VT_INTERNAL_H -#define AVCODEC_VDA_VT_INTERNAL_H - -void ff_vda_output_callback(void *vda_hw_ctx, - CFDictionaryRef user_info, - OSStatus status, - uint32_t infoFlags, - CVImageBufferRef image_buffer); - -int ff_vda_default_init(AVCodecContext *avctx); -void ff_vda_default_free(AVCodecContext *avctx); +#ifndef AVCODEC_VT_INTERNAL_H +#define AVCODEC_VT_INTERNAL_H typedef struct VTContext { // The current bitstream buffer. @@ -47,6 +38,10 @@ typedef struct VTContext { // Non-NULL if the new hwaccel API is used. This is only a separate struct // to ease compatibility with the old API. struct AVVideotoolboxContext *vt_ctx; + + // Current H264 parameters (used to trigger decoder restart on SPS changes). + uint8_t sps[3]; + bool reconfig_needed; } VTContext; int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame); @@ -60,4 +55,5 @@ int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx, uint32_t size); CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx); -#endif /* AVCODEC_VDA_VT_INTERNAL_H */ + +#endif /* AVCODEC_VT_INTERNAL_H */ diff --git a/libavcodec/webp.c b/libavcodec/webp.c index efa864a6f..077bb06f8 100644 --- a/libavcodec/webp.c +++ b/libavcodec/webp.c @@ -1335,6 +1335,7 @@ static int vp8_lossy_decode_frame(AVCodecContext *avctx, AVFrame *p, if (!s->initialized) { ff_vp8_decode_init(avctx); s->initialized = 1; + s->v.actually_webp = 1; } avctx->pix_fmt = s->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; s->lossless = 0; @@ -1504,7 +1505,7 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } bytestream2_seek(&exif_gb, ifd_offset, SEEK_SET); - if (avpriv_exif_decode_ifd(avctx, &exif_gb, le, 0, &exif_metadata) < 0) { + if (ff_exif_decode_ifd(avctx, &exif_gb, le, 0, &exif_metadata) < 0) { av_log(avctx, AV_LOG_ERROR, "error decoding Exif data\n"); goto exif_end; } diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c index 2ec449998..3f86d0da3 100644 --- a/libavcodec/wmavoice.c +++ b/libavcodec/wmavoice.c @@ -1756,6 +1756,10 @@ static int synth_superframe(AVCodecContext *ctx, AVFrame *frame, stabilize_lsps(lsps[n], s->lsps); } + /* synth_superframe can run multiple times per packet + * free potential previous frame */ + av_frame_unref(frame); + /* get output buffer */ frame->nb_samples = MAX_SFRAMESIZE; if ((res = ff_get_buffer(ctx, frame, 0)) < 0) diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c index 20dbee570..ea0e0594b 100644 --- a/libavcodec/wmv2dec.c +++ b/libavcodec/wmv2dec.c @@ -30,7 +30,7 @@ #include "wmv2.h" -static void parse_mb_skip(Wmv2Context *w) +static int parse_mb_skip(Wmv2Context *w) { int mb_x, mb_y; MpegEncContext *const s = &w->s; @@ -45,6 +45,8 @@ static void parse_mb_skip(Wmv2Context *w) MB_TYPE_16x16 | MB_TYPE_L0; break; case SKIP_TYPE_MPEG: + if (get_bits_left(&s->gb) < s->mb_height * s->mb_width) + return AVERROR_INVALIDDATA; for (mb_y = 0; mb_y < s->mb_height; mb_y++) for (mb_x = 0; mb_x < s->mb_width; mb_x++) mb_type[mb_y * s->mb_stride + mb_x] = @@ -52,6 +54,8 @@ static void parse_mb_skip(Wmv2Context *w) break; case SKIP_TYPE_ROW: for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + if (get_bits_left(&s->gb) < 1) + return AVERROR_INVALIDDATA; if (get_bits1(&s->gb)) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) mb_type[mb_y * s->mb_stride + mb_x] = @@ -65,6 +69,8 @@ static void parse_mb_skip(Wmv2Context *w) break; case SKIP_TYPE_COL: for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + if (get_bits_left(&s->gb) < 1) + return AVERROR_INVALIDDATA; if (get_bits1(&s->gb)) { for (mb_y = 0; mb_y < s->mb_height; mb_y++) mb_type[mb_y * s->mb_stride + mb_x] = @@ -77,6 +83,7 @@ static void parse_mb_skip(Wmv2Context *w) } break; } + return 0; } static int decode_ext_header(Wmv2Context *w) @@ -170,9 +177,12 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) } } else { int cbp_index; + int ret; w->j_type = 0; - parse_mb_skip(w); + ret = parse_mb_skip(w); + if (ret < 0) + return ret; cbp_index = decode012(&s->gb); w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index); @@ -359,6 +369,8 @@ int ff_wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) w->hshift = 0; return 0; } + if (get_bits_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; code = get_vlc2(&s->gb, ff_mb_non_intra_vlc[w->cbp_table_index].table, MB_NON_INTRA_VLC_BITS, 3); @@ -369,6 +381,8 @@ int ff_wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) cbp = code & 0x3f; } else { s->mb_intra = 1; + if (get_bits_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; code = get_vlc2(&s->gb, ff_msmp4_mb_i_vlc.table, MB_INTRA_VLC_BITS, 2); if (code < 0) { av_log(s->avctx, AV_LOG_ERROR, @@ -460,10 +474,6 @@ static av_cold int wmv2_decode_init(AVCodecContext *avctx) Wmv2Context *const w = avctx->priv_data; int ret; -#if FF_API_EMU_EDGE - avctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif - if ((ret = ff_msmpeg4_decode_init(avctx)) < 0) return ret; diff --git a/libavcodec/wrapped_avframe.c b/libavcodec/wrapped_avframe.c index 5f88a668b..85ff32d13 100644 --- a/libavcodec/wrapped_avframe.c +++ b/libavcodec/wrapped_avframe.c @@ -25,6 +25,7 @@ */ #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "libavutil/internal.h" @@ -98,6 +99,12 @@ static int wrapped_avframe_decode(AVCodecContext *avctx, void *data, av_frame_move_ref(out, in); + err = ff_attach_decode_data(out); + if (err < 0) { + av_frame_unref(out); + return err; + } + *got_frame = 1; return 0; } diff --git a/libavcodec/x86/audiodsp.asm b/libavcodec/x86/audiodsp.asm index 3973808ca..de395e5fa 100644 --- a/libavcodec/x86/audiodsp.asm +++ b/libavcodec/x86/audiodsp.asm @@ -62,7 +62,7 @@ SCALARPRODUCT ; %1 = number of xmm registers used ; %2 = number of inline load/process/store loops per asm loop ; %3 = process 4*mmsize (%3=0) or 8*mmsize (%3=1) bytes per loop -; %4 = CLIPD function takes min/max as float instead of int (CLIPD_SSE2) +; %4 = CLIPD function takes min/max as float instead of int (SSE2 version) ; %5 = suffix %macro VECTOR_CLIP_INT32 4-5 cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len @@ -118,14 +118,11 @@ cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len %endmacro INIT_MMX mmx -%define CLIPD CLIPD_MMX VECTOR_CLIP_INT32 0, 1, 0, 0 INIT_XMM sse2 VECTOR_CLIP_INT32 6, 1, 0, 0, _int -%define CLIPD CLIPD_SSE2 VECTOR_CLIP_INT32 6, 2, 0, 1 INIT_XMM sse4 -%define CLIPD CLIPD_SSE41 %ifdef m8 VECTOR_CLIP_INT32 11, 1, 1, 0 %else diff --git a/libavcodec/x86/bswapdsp.asm b/libavcodec/x86/bswapdsp.asm index 56d808362..31c6c48a2 100644 --- a/libavcodec/x86/bswapdsp.asm +++ b/libavcodec/x86/bswapdsp.asm @@ -35,14 +35,18 @@ SECTION .text mov r3d, r2d sar r2d, 3 jz .left4_%1 +%if cpuflag(avx2) + sar r2d, 1 + jz .left8_%1 +%endif .loop8_%1: mov%1 m0, [r1 + 0] - mov%1 m1, [r1 + 16] -%if cpuflag(ssse3) + mov%1 m1, [r1 + mmsize] +%if cpuflag(ssse3)||cpuflag(avx2) pshufb m0, m2 pshufb m1, m2 mov%1 [r0 + 0], m0 - mov%1 [r0 + 16], m1 + mov%1 [r0 + mmsize], m1 %else pshuflw m0, m0, 10110001b pshuflw m1, m1, 10110001b @@ -59,18 +63,29 @@ SECTION .text mov%1 [r0 + 0], m2 mov%1 [r0 + 16], m3 %endif - add r0, 32 - add r1, 32 + add r0, mmsize*2 + add r1, mmsize*2 dec r2d jnz .loop8_%1 +%if cpuflag(avx2) +.left8_%1: + mov r2d, r3d + test r3d, 8 + jz .left4_%1 + mov%1 m0, [r1] + pshufb m0, m2 + mov%1 [r0 + 0], m0 + add r1, mmsize + add r0, mmsize +%endif .left4_%1: mov r2d, r3d test r3d, 4 jz .left - mov%1 m0, [r1] + mov%1 xm0, [r1] %if cpuflag(ssse3) - pshufb m0, m2 - mov%1 [r0], m0 + pshufb xm0, xm2 + mov%1 [r0], xm0 %else pshuflw m0, m0, 10110001b pshufhw m0, m0, 10110001b @@ -86,16 +101,16 @@ SECTION .text ; void ff_bswap_buf(uint32_t *dst, const uint32_t *src, int w); %macro BSWAP32_BUF 0 -%if cpuflag(ssse3) +%if cpuflag(ssse3)||cpuflag(avx2) cglobal bswap32_buf, 3,4,3 mov r3, r1 - mova m2, [pb_bswap32] + VBROADCASTI128 m2, [pb_bswap32] %else cglobal bswap32_buf, 3,4,5 mov r3, r1 %endif or r3, r0 - test r3, 15 + test r3, mmsize - 1 jz .start_align BSWAP_LOOPS u jmp .left @@ -105,9 +120,9 @@ cglobal bswap32_buf, 3,4,5 %if cpuflag(ssse3) test r2d, 2 jz .left1 - movq m0, [r1] - pshufb m0, m2 - movq [r0], m0 + movq xm0, [r1] + pshufb xm0, xm2 + movq [r0], xm0 add r1, 8 add r0, 8 .left1: @@ -137,3 +152,8 @@ BSWAP32_BUF INIT_XMM ssse3 BSWAP32_BUF + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +BSWAP32_BUF +%endif diff --git a/libavcodec/x86/bswapdsp_init.c b/libavcodec/x86/bswapdsp_init.c index c042e5637..877bab1a2 100644 --- a/libavcodec/x86/bswapdsp_init.c +++ b/libavcodec/x86/bswapdsp_init.c @@ -25,6 +25,7 @@ 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) { @@ -34,4 +35,6 @@ av_cold void ff_bswapdsp_init_x86(BswapDSPContext *c) 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/libavcodec/x86/constants.c b/libavcodec/x86/constants.c index 11002ee61..4bfb78cc3 100644 --- a/libavcodec/x86/constants.c +++ b/libavcodec/x86/constants.c @@ -26,23 +26,23 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1) = { 0x0001000100010001ULL, 0x000 0x0001000100010001ULL, 0x0001000100010001ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pw_2) = { 0x0002000200020002ULL, 0x0002000200020002ULL, 0x0002000200020002ULL, 0x0002000200020002ULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0x0003000300030003ULL }; -DECLARE_ALIGNED(32, const ymm_reg, ff_pw_4) = { 0x0004000400040004ULL, 0x0004000400040004ULL, +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_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_8) = { 0x0008000800080008ULL, 0x0008000800080008ULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_9) = { 0x0009000900090009ULL, 0x0009000900090009ULL }; +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_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL }; +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_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL }; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL; +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, @@ -74,7 +74,8 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pb_2) = { 0x0202020202020202ULL, 0x020 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(16, const xmm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x8080808080808080ULL }; +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; diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h index bbb0ef844..85da38b7b 100644 --- a/libavcodec/x86/constants.h +++ b/libavcodec/x86/constants.h @@ -57,7 +57,7 @@ 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 xmm_reg ff_pb_80; +extern const ymm_reg ff_pb_80; extern const ymm_reg ff_pb_FE; extern const uint64_t ff_pb_FC; diff --git a/libavcodec/x86/dct32.asm b/libavcodec/x86/dct32.asm index 4e657b546..21e2f21c9 100644 --- a/libavcodec/x86/dct32.asm +++ b/libavcodec/x86/dct32.asm @@ -23,7 +23,8 @@ SECTION_RODATA 32 -align 32 +ps_p1p1m1m1: dd 0, 0, 0x80000000, 0x80000000, 0, 0, 0x80000000, 0x80000000 + ps_cos_vec: dd 0.500603, 0.505471, 0.515447, 0.531043 dd 0.553104, 0.582935, 0.622504, 0.674808 dd -10.190008, -3.407609, -2.057781, -1.484165 @@ -38,9 +39,6 @@ ps_cos_vec: dd 0.500603, 0.505471, 0.515447, 0.531043 dd 1.000000, 0.707107, 1.000000, -0.707107 dd 0.707107, 0.707107, 0.707107, 0.707107 -align 32 -ps_p1p1m1m1: dd 0, 0, 0x80000000, 0x80000000, 0, 0, 0x80000000, 0x80000000 - %macro BUTTERFLY 4 subps %4, %1, %2 addps %2, %2, %1 diff --git a/libavcodec/x86/exrdsp.asm b/libavcodec/x86/exrdsp.asm index 23c9397ef..3bf240c8b 100644 --- a/libavcodec/x86/exrdsp.asm +++ b/libavcodec/x86/exrdsp.asm @@ -73,11 +73,7 @@ REORDER_PIXELS %macro PREDICTOR 0 cglobal predictor, 2,2,5, src, size -%if mmsize == 32 - vbroadcasti128 m0, [pb_80] -%else - mova xm0, [pb_80] -%endif + mova m0, [pb_80] mova xm1, [pb_15] mova xm2, xm0 add srcq, sizeq diff --git a/libavcodec/x86/fft.asm b/libavcodec/x86/fft.asm index cdbfd66e8..a671e8f48 100644 --- a/libavcodec/x86/fft.asm +++ b/libavcodec/x86/fft.asm @@ -191,6 +191,23 @@ SECTION .text 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) @@ -541,17 +558,6 @@ DEFINE_ARGS zc, w, n, o1, o3 INIT_YMM avx %if HAVE_AVX_EXTERNAL -%macro INTERL_AVX 5 - 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 -%endmacro - -%define INTERL INTERL_AVX - DECL_PASS pass_avx, PASS_BIG 1 DECL_PASS pass_interleave_avx, PASS_BIG 0 @@ -566,16 +572,6 @@ cglobal fft_calc, 2,5,8 INIT_XMM sse -%macro INTERL_SSE 5 - mova %3, %2 - unpcklps %2, %1 - unpckhps %3, %1 - mova %4(%5), %2 - mova %4(%5+1), %3 -%endmacro - -%define INTERL INTERL_SSE - DECL_PASS pass_sse, PASS_BIG 1 DECL_PASS pass_interleave_sse, PASS_BIG 0 @@ -861,16 +857,30 @@ INIT_XMM sse %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_AVX 5 ;j, k, z+n8, tcos+n8, tsin+n8 +%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] @@ -899,10 +909,7 @@ INIT_XMM sse sub %2, 0x20 add %1, 0x20 jl .post -%endmacro - -%macro POSROTATESHUF 5 ;j, k, z+n8, tcos+n8, tsin+n8 -.post: +%elif cpuflag(sse) movaps xmm1, [%3+%1*2] movaps xmm0, [%3+%1*2+0x10] CMUL %1, xmm0, xmm1, %3, %4, %5 @@ -924,25 +931,9 @@ INIT_XMM sse sub %2, 0x10 add %1, 0x10 jl .post -%endmacro - -%macro CMUL_3DNOW 6 - 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 -%endmacro - -%macro POSROTATESHUF_3DNOW 5 ;j, k, z+n8, tcos+n8, tsin+n8 -.post: - CMUL_3DNOW %3, %1, m0, m1, %4, %5 - CMUL_3DNOW %3, %2, m2, m3, %4, %5 +%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 @@ -958,9 +949,10 @@ INIT_XMM sse sub %2, 8 add %1, 8 jl .post +%endif %endmacro -%macro DECL_IMDCT 1 +%macro DECL_IMDCT 0 cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *input %if ARCH_X86_64 %define rrevtab r7 @@ -1066,7 +1058,7 @@ cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *i neg r0 mov r1, -mmsize sub r1, r0 - %1 r0, r1, r6, rtcos, rtsin + POSROTATESHUF r0, r1, r6, rtcos, rtsin %if ARCH_X86_64 == 0 add esp, 12 %endif @@ -1076,18 +1068,18 @@ cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *i RET %endmacro -DECL_IMDCT POSROTATESHUF +DECL_IMDCT %if ARCH_X86_32 INIT_MMX 3dnow -DECL_IMDCT POSROTATESHUF_3DNOW +DECL_IMDCT INIT_MMX 3dnowext -DECL_IMDCT POSROTATESHUF_3DNOW +DECL_IMDCT %endif INIT_YMM avx %if HAVE_AVX_EXTERNAL -DECL_IMDCT POSROTATESHUF_AVX +DECL_IMDCT %endif diff --git a/libavcodec/x86/h264_idct.asm b/libavcodec/x86/h264_idct.asm index ea91e1ac4..880463809 100644 --- a/libavcodec/x86/h264_idct.asm +++ b/libavcodec/x86/h264_idct.asm @@ -995,7 +995,30 @@ REP_RET SWAP %1, %4, %3 %endmacro -%macro DEQUANT_MMX 3 +%macro DEQUANT 1-3 +%if cpuflag(sse2) + movd xmm4, t3d + movq xmm5, [pw_1] + pshufd xmm4, xmm4, 0 + movq2dq xmm0, m0 + movq2dq xmm1, m1 + movq2dq xmm2, m2 + movq2dq xmm3, m3 + punpcklwd xmm0, xmm5 + punpcklwd xmm1, xmm5 + punpcklwd xmm2, xmm5 + punpcklwd xmm3, xmm5 + pmaddwd xmm0, xmm4 + pmaddwd xmm1, xmm4 + pmaddwd xmm2, xmm4 + pmaddwd xmm3, xmm4 + psrad xmm0, %1 + psrad xmm1, %1 + psrad xmm2, %1 + psrad xmm3, %1 + packssdw xmm0, xmm1 + packssdw xmm2, xmm3 +%else mova m7, [pw_1] mova m4, %1 punpcklwd %1, m7 @@ -1015,6 +1038,7 @@ REP_RET psrad m5, %3 packssdw %1, m4 packssdw %2, m5 +%endif %endmacro %macro STORE_WORDS 5-9 @@ -1053,35 +1077,15 @@ REP_RET %macro DEQUANT_STORE 1 %if cpuflag(sse2) - movd xmm4, t3d - movq xmm5, [pw_1] - pshufd xmm4, xmm4, 0 - movq2dq xmm0, m0 - movq2dq xmm1, m1 - movq2dq xmm2, m2 - movq2dq xmm3, m3 - punpcklwd xmm0, xmm5 - punpcklwd xmm1, xmm5 - punpcklwd xmm2, xmm5 - punpcklwd xmm3, xmm5 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm4 - pmaddwd xmm3, xmm4 - psrad xmm0, %1 - psrad xmm1, %1 - psrad xmm2, %1 - psrad xmm3, %1 - packssdw xmm0, xmm1 - packssdw xmm2, xmm3 + DEQUANT %1 STORE_WORDS xmm0, 0, 1, 4, 5, 2, 3, 6, 7 STORE_WORDS xmm2, 8, 9, 12, 13, 10, 11, 14, 15 %else - DEQUANT_MMX m0, m1, %1 + DEQUANT m0, m1, %1 STORE_WORDS m0, 0, 1, 4, 5 STORE_WORDS m1, 2, 3, 6, 7 - DEQUANT_MMX m2, m3, %1 + DEQUANT m2, m3, %1 STORE_WORDS m2, 8, 9, 12, 13 STORE_WORDS m3, 10, 11, 14, 15 %endif diff --git a/libavcodec/x86/hevc_sao.asm b/libavcodec/x86/hevc_sao.asm index 888a28afa..756adfee5 100644 --- a/libavcodec/x86/hevc_sao.asm +++ b/libavcodec/x86/hevc_sao.asm @@ -198,7 +198,7 @@ HEVC_SAO_BAND_FILTER 64, 2 ;****************************************************************************** %define MAX_PB_SIZE 64 -%define PADDING_SIZE 32 ; AV_INPUT_BUFFER_PADDING_SIZE +%define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE %macro HEVC_SAO_EDGE_FILTER_INIT 0 diff --git a/libavcodec/x86/hevc_sao_10bit.asm b/libavcodec/x86/hevc_sao_10bit.asm index f81e2d503..b30583dd2 100644 --- a/libavcodec/x86/hevc_sao_10bit.asm +++ b/libavcodec/x86/hevc_sao_10bit.asm @@ -190,7 +190,7 @@ HEVC_SAO_BAND_FILTER 12, 64, 4 ;****************************************************************************** %define MAX_PB_SIZE 64 -%define PADDING_SIZE 32 ; AV_INPUT_BUFFER_PADDING_SIZE +%define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE %macro PMINUW 4 diff --git a/libavcodec/x86/huffyuvdsp.asm b/libavcodec/x86/huffyuvdsp.asm index 0d8cae354..a1231f1b2 100644 --- a/libavcodec/x86/huffyuvdsp.asm +++ b/libavcodec/x86/huffyuvdsp.asm @@ -24,77 +24,39 @@ SECTION .text +%include "libavcodec/x86/huffyuvdsp_template.asm" -%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub - movd m4, maskd - SPLATW m4, m4 - add wd, wd - test wq, 2*mmsize - 1 - jz %%.tomainloop - push tmpq -%%.wordloop: - sub wq, 2 -%ifidn %2, add - mov tmpw, [srcq+wq] - add tmpw, [dstq+wq] -%else - mov tmpw, [src1q+wq] - sub tmpw, [src2q+wq] -%endif - and tmpw, maskw - mov [dstq+wq], tmpw - test wq, 2*mmsize - 1 - jnz %%.wordloop - pop tmpq -%%.tomainloop: -%ifidn %2, add - add srcq, wq -%else - add src1q, wq - add src2q, wq -%endif - add dstq, wq - neg wq - jz %%.end -%%.loop: -%ifidn %2, add - mov%1 m0, [srcq+wq] - mov%1 m1, [dstq+wq] - mov%1 m2, [srcq+wq+mmsize] - mov%1 m3, [dstq+wq+mmsize] -%else - mov%1 m0, [src1q+wq] - mov%1 m1, [src2q+wq] - mov%1 m2, [src1q+wq+mmsize] - mov%1 m3, [src2q+wq+mmsize] -%endif - p%2w m0, m1 - p%2w m2, m3 - pand m0, m4 - pand m2, m4 - mov%1 [dstq+wq] , m0 - mov%1 [dstq+wq+mmsize], m2 - add wq, 2*mmsize - jl %%.loop -%%.end: - RET -%endmacro +;------------------------------------------------------------------------------ +; void (*add_int16)(uint16_t *dst, const uint16_t *src, unsigned mask, int w); +;------------------------------------------------------------------------------ -%if ARCH_X86_32 -INIT_MMX mmx -cglobal add_int16, 4,4,5, dst, src, mask, w, tmp - INT16_LOOP a, add -%endif - -INIT_XMM sse2 +%macro ADD_INT16 0 cglobal add_int16, 4,4,5, dst, src, mask, w, tmp +%if mmsize > 8 test srcq, mmsize-1 jnz .unaligned test dstq, mmsize-1 jnz .unaligned +%endif INT16_LOOP a, add +%if mmsize > 8 .unaligned: INT16_LOOP u, add +%endif +%endmacro + +%if ARCH_X86_32 +INIT_MMX mmx +ADD_INT16 +%endif + +INIT_XMM sse2 +ADD_INT16 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_INT16 +%endif ; void add_hfyu_left_pred_bgr32(uint8_t *dst, const uint8_t *src, ; intptr_t w, uint8_t *left) diff --git a/libavcodec/x86/huffyuvdsp_init.c b/libavcodec/x86/huffyuvdsp_init.c index 26cf6214d..eb10de383 100644 --- a/libavcodec/x86/huffyuvdsp_init.c +++ b/libavcodec/x86/huffyuvdsp_init.c @@ -28,6 +28,8 @@ 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, @@ -52,4 +54,8 @@ av_cold void ff_huffyuvdsp_init_x86(HuffYUVDSPContext *c, enum AVPixelFormat pix 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/libavcodec/x86/huffyuvdsp_template.asm b/libavcodec/x86/huffyuvdsp_template.asm new file mode 100644 index 000000000..89721f4ec --- /dev/null +++ b/libavcodec/x86/huffyuvdsp_template.asm @@ -0,0 +1,76 @@ +;****************************************************************************** +;* SIMD-optimized HuffYUV functions +;* Copyright (c) 2008 Loren Merritt +;* Copyright (c) 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 +;****************************************************************************** + +%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub + movd xm4, maskd + SPLATW m4, xm4 + add wd, wd + test wq, 2*mmsize - 1 + jz %%.tomainloop + push tmpq +%%.wordloop: + sub wq, 2 +%ifidn %2, add + mov tmpw, [srcq+wq] + add tmpw, [dstq+wq] +%else + mov tmpw, [src1q+wq] + sub tmpw, [src2q+wq] +%endif + and tmpw, maskw + mov [dstq+wq], tmpw + test wq, 2*mmsize - 1 + jnz %%.wordloop + pop tmpq +%%.tomainloop: +%ifidn %2, add + add srcq, wq +%else + add src1q, wq + add src2q, wq +%endif + add dstq, wq + neg wq + jz %%.end +%%.loop: +%ifidn %2, add + mov%1 m0, [srcq+wq] + mov%1 m1, [dstq+wq] + mov%1 m2, [srcq+wq+mmsize] + mov%1 m3, [dstq+wq+mmsize] +%else + mov%1 m0, [src1q+wq] + mov%1 m1, [src2q+wq] + mov%1 m2, [src1q+wq+mmsize] + mov%1 m3, [src2q+wq+mmsize] +%endif + p%2w m0, m1 + p%2w m2, m3 + pand m0, m4 + pand m2, m4 + mov%1 [dstq+wq] , m0 + mov%1 [dstq+wq+mmsize], m2 + add wq, 2*mmsize + jl %%.loop +%%.end: + RET +%endmacro diff --git a/libavcodec/x86/huffyuvencdsp.asm b/libavcodec/x86/huffyuvencdsp.asm index eeef81ab8..d994fd0fd 100644 --- a/libavcodec/x86/huffyuvencdsp.asm +++ b/libavcodec/x86/huffyuvencdsp.asm @@ -27,80 +27,42 @@ SECTION .text +%include "libavcodec/x86/huffyuvdsp_template.asm" + +;------------------------------------------------------------------------------ ; void ff_diff_int16(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, ; unsigned mask, int w); -%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub - movd m4, maskd - SPLATW m4, m4 - add wd, wd - test wq, 2*mmsize - 1 - jz %%.tomainloop - push tmpq -%%.wordloop: - sub wq, 2 -%ifidn %2, add - mov tmpw, [srcq+wq] - add tmpw, [dstq+wq] -%else - mov tmpw, [src1q+wq] - sub tmpw, [src2q+wq] -%endif - and tmpw, maskw - mov [dstq+wq], tmpw - test wq, 2*mmsize - 1 - jnz %%.wordloop - pop tmpq -%%.tomainloop: -%ifidn %2, add - add srcq, wq -%else - add src1q, wq - add src2q, wq -%endif - add dstq, wq - neg wq - jz %%.end -%%.loop: -%ifidn %2, add - mov%1 m0, [srcq+wq] - mov%1 m1, [dstq+wq] - mov%1 m2, [srcq+wq+mmsize] - mov%1 m3, [dstq+wq+mmsize] -%else - mov%1 m0, [src1q+wq] - mov%1 m1, [src2q+wq] - mov%1 m2, [src1q+wq+mmsize] - mov%1 m3, [src2q+wq+mmsize] -%endif - p%2w m0, m1 - p%2w m2, m3 - pand m0, m4 - pand m2, m4 - mov%1 [dstq+wq] , m0 - mov%1 [dstq+wq+mmsize], m2 - add wq, 2*mmsize - jl %%.loop -%%.end: - RET -%endmacro +;------------------------------------------------------------------------------ -%if ARCH_X86_32 -INIT_MMX mmx -cglobal diff_int16, 5,5,5, dst, src1, src2, mask, w, tmp - INT16_LOOP a, sub -%endif - -INIT_XMM sse2 +%macro DIFF_INT16 0 cglobal diff_int16, 5,5,5, dst, src1, src2, mask, w, tmp +%if mmsize > 8 test src1q, mmsize-1 jnz .unaligned test src2q, mmsize-1 jnz .unaligned test dstq, mmsize-1 jnz .unaligned +%endif INT16_LOOP a, sub +%if mmsize > 8 .unaligned: INT16_LOOP u, sub +%endif +%endmacro + +%if ARCH_X86_32 +INIT_MMX mmx +DIFF_INT16 +%endif + +INIT_XMM sse2 +DIFF_INT16 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +DIFF_INT16 +%endif INIT_MMX mmxext cglobal sub_hfyu_median_pred_int16, 7,7,0, dst, src1, src2, mask, w, left, left_top diff --git a/libavcodec/x86/huffyuvencdsp_init.c b/libavcodec/x86/huffyuvencdsp_init.c index f66bc8c4f..6c6e068cf 100644 --- a/libavcodec/x86/huffyuvencdsp_init.c +++ b/libavcodec/x86/huffyuvencdsp_init.c @@ -32,6 +32,8 @@ void ff_diff_int16_mmx (uint16_t *dst, const uint16_t *src1, const uint16_t *src 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); @@ -51,4 +53,8 @@ av_cold void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, AVCodecContext * 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/libavcodec/x86/imdct36.asm b/libavcodec/x86/imdct36.asm index 960eabdda..b386ab95f 100644 --- a/libavcodec/x86/imdct36.asm +++ b/libavcodec/x86/imdct36.asm @@ -23,7 +23,6 @@ SECTION_RODATA -align 16 ps_mask: dd 0, ~0, ~0, ~0 ps_mask2: dd 0, ~0, 0, ~0 ps_mask3: dd 0, 0, 0, ~0 diff --git a/libavcodec/x86/jpeg2000dsp.asm b/libavcodec/x86/jpeg2000dsp.asm index 56b5fbd60..61dfdd4f7 100644 --- a/libavcodec/x86/jpeg2000dsp.asm +++ b/libavcodec/x86/jpeg2000dsp.asm @@ -74,6 +74,19 @@ align 16 movaps m1, [src1q+csizeq] movaps m2, [src2q+csizeq] +%if cpuflag(fma4) || cpuflag(fma3) +%if cpuflag(fma4) + fnmaddps m5, m1, ICT1, m0 + fmaddps m4, m2, ICT0, m0 +%else ; fma3 + movaps m5, m1 + movaps m4, m2 + fnmaddps m5, m5, ICT1, m0 + fmaddps m4, m4, ICT0, m0 +%endif + fmaddps m0, m1, ICT3, m0 + fnmaddps m5, m2, ICT2, m5 +%else ; non FMA %if cpuflag(avx) mulps m5, m1, ICT1 mulps m4, m2, ICT0 @@ -93,6 +106,7 @@ align 16 addps m4, m4, m0 addps m0, m0, m1 subps m5, m5, m2 +%endif movaps [src0q+csizeq], m4 movaps [src2q+csizeq], m0 @@ -106,6 +120,12 @@ INIT_XMM sse ICT_FLOAT 10 INIT_YMM avx ICT_FLOAT 9 +%if HAVE_FMA4_EXTERNAL +INIT_XMM fma4 +ICT_FLOAT 9 +%endif +INIT_YMM fma3 +ICT_FLOAT 9 ;*************************************************************************** ; ff_rct_int_(int32_t *src0, int32_t *src1, int32_t *src2, int csize) diff --git a/libavcodec/x86/jpeg2000dsp_init.c b/libavcodec/x86/jpeg2000dsp_init.c index baa81383e..7310a1d0e 100644 --- a/libavcodec/x86/jpeg2000dsp_init.c +++ b/libavcodec/x86/jpeg2000dsp_init.c @@ -26,6 +26,8 @@ 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); @@ -44,6 +46,14 @@ av_cold void ff_jpeg2000dsp_init_x86(Jpeg2000DSPContext *c) 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/libavcodec/x86/lossless_videodsp.asm b/libavcodec/x86/lossless_videodsp.asm index 443fe0295..0a1b7091c 100644 --- a/libavcodec/x86/lossless_videodsp.asm +++ b/libavcodec/x86/lossless_videodsp.asm @@ -2,6 +2,7 @@ ;* SIMD lossless video DSP utils ;* Copyright (c) 2008 Loren Merritt ;* Copyright (c) 2014 Michael Niedermayer +;* Copyright (c) 2017 Jokyo Images ;* ;* This file is part of FFmpeg. ;* @@ -36,9 +37,11 @@ pb_zzzzzzzz67676767: db -1,-1,-1,-1,-1,-1,-1,-1, 6, 7, 6, 7, 6, 7, 6, 7 SECTION .text +;------------------------------------------------------------------------------ ; void ff_add_median_pred_mmxext(uint8_t *dst, const uint8_t *top, ; const uint8_t *diff, int w, ; int *left, int *left_top) +;------------------------------------------------------------------------------ %macro MEDIAN_PRED 0 cglobal add_median_pred, 6,6,8, dst, top, diff, w, left, left_top movu m0, [topq] @@ -112,44 +115,59 @@ MEDIAN_PRED add dstq, wq neg wq %%.loop: + pshufb xm0, xm5 %if %2 mova m1, [srcq+wq] %else movu m1, [srcq+wq] %endif - mova m2, m1 - psllw m1, 8 + psllw m2, m1, 8 paddb m1, m2 - mova m2, m1 - pshufb m1, m3 + pshufb m2, m1, m3 paddb m1, m2 - pshufb m0, m5 - mova m2, m1 - pshufb m1, m4 + pshufb m2, m1, m4 paddb m1, m2 -%if mmsize == 16 - mova m2, m1 - pshufb m1, m6 +%if mmsize >= 16 + pshufb m2, m1, m6 paddb m1, m2 %endif - paddb m0, m1 + paddb xm0, xm1 %if %1 - mova [dstq+wq], m0 + mova [dstq+wq], xm0 %else - movq [dstq+wq], m0 - movhps [dstq+wq+8], m0 + movq [dstq+wq], xm0 + movhps [dstq+wq+8], xm0 +%endif + +%if mmsize == 32 + vextracti128 xm2, m1, 1 ; get second lane of the ymm + pshufb xm0, xm5 ; set alls val to last val of the first lane + paddb xm0, xm2 +;store val +%if %1 + mova [dstq+wq+16], xm0 +%else; + movq [dstq+wq+16], xm0 + movhps [dstq+wq+16+8], xm0 +%endif %endif add wq, mmsize jl %%.loop +%if mmsize == 32 + movzx eax, byte [dstq - 1] +%else; mov eax, mmsize-1 sub eax, wd movd m1, eax pshufb m0, m1 movd eax, m0 +%endif RET %endmacro +;------------------------------------------------------------------------------ ; int ff_add_left_pred(uint8_t *dst, const uint8_t *src, int w, int left) +;------------------------------------------------------------------------------ INIT_MMX ssse3 cglobal add_left_pred, 3,3,7, dst, src, w, left .skip_prologue: @@ -160,24 +178,36 @@ cglobal add_left_pred, 3,3,7, dst, src, w, left psllq m0, 56 ADD_LEFT_LOOP 1, 1 -INIT_XMM ssse3 +%macro ADD_LEFT_PRED_UNALIGNED 0 cglobal add_left_pred_unaligned, 3,3,7, dst, src, w, left - mova m5, [pb_15] - mova m6, [pb_zzzzzzzz77777777] - mova m4, [pb_zzzz3333zzzzbbbb] - mova m3, [pb_zz11zz55zz99zzdd] - movd m0, leftm - pslldq m0, 15 - test srcq, 15 + mova xm5, [pb_15] + VBROADCASTI128 m6, [pb_zzzzzzzz77777777] + VBROADCASTI128 m4, [pb_zzzz3333zzzzbbbb] + VBROADCASTI128 m3, [pb_zz11zz55zz99zzdd] + movd xm0, leftm + pslldq xm0, 15 + test srcq, mmsize - 1 jnz .src_unaligned - test dstq, 15 + test dstq, mmsize - 1 jnz .dst_unaligned ADD_LEFT_LOOP 1, 1 .dst_unaligned: ADD_LEFT_LOOP 0, 1 .src_unaligned: ADD_LEFT_LOOP 0, 0 +%endmacro +INIT_XMM ssse3 +ADD_LEFT_PRED_UNALIGNED + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_LEFT_PRED_UNALIGNED +%endif + +;------------------------------------------------------------------------------ +; void ff_add_bytes(uint8_t *dst, uint8_t *src, ptrdiff_t w); +;------------------------------------------------------------------------------ %macro ADD_BYTES 0 cglobal add_bytes, 3,4,2, dst, src, w, size mov sizeq, wq @@ -217,6 +247,11 @@ ADD_BYTES INIT_XMM sse2 ADD_BYTES +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_BYTES +%endif + %macro ADD_HFYU_LEFT_LOOP_INT16 2 ; %1 = dst alignment (a/u), %2 = src alignment (a/u) add wd, wd add srcq, wq @@ -258,7 +293,9 @@ ADD_BYTES RET %endmacro +;--------------------------------------------------------------------------------------------- ; int add_left_pred_int16(uint16_t *dst, const uint16_t *src, unsigned mask, int w, int left) +;--------------------------------------------------------------------------------------------- INIT_MMX ssse3 cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left .skip_prologue: @@ -270,8 +307,8 @@ cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left SPLATW m7 ,m7 ADD_HFYU_LEFT_LOOP_INT16 a, a -INIT_XMM sse4 -cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left +INIT_XMM ssse3 +cglobal add_left_pred_int16_unaligned, 4,4,8, dst, src, mask, w, left mova m5, [pb_ef] mova m4, [pb_zzzzzzzz67676767] mova m3, [pb_zzzz2323zzzzabab] @@ -288,3 +325,82 @@ cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left ADD_HFYU_LEFT_LOOP_INT16 u, a .src_unaligned: ADD_HFYU_LEFT_LOOP_INT16 u, u + + +;--------------------------------------------------------------------------------------------- +; void add_gradient_pred(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width) +;--------------------------------------------------------------------------------------------- +%macro ADD_GRADIENT_PRED 0 +cglobal add_gradient_pred, 3,4,5, src, stride, width, tmp + mova xm0, [pb_15] + +;load src - 1 in xm1 + movd xm1, [srcq-1] +%if cpuflag(avx2) + vpbroadcastb xm1, xm1 +%else + pxor xm2, xm2 + pshufb xm1, xm2 +%endif + + add srcq, widthq + neg widthq + neg strideq + +.loop: + lea tmpq, [srcq + strideq] + mova m2, [tmpq + widthq] ; A = src[x-stride] + movu m3, [tmpq + widthq - 1] ; B = src[x - (stride + 1)] + mova m4, [srcq + widthq] ; current val (src[x]) + + psubb m2, m3; A - B + +; prefix sum A-B + pslldq m3, m2, 1 + paddb m2, m3 + pslldq m3, m2, 2 + paddb m2, m3 + pslldq m3, m2, 4 + paddb m2, m3 + pslldq m3, m2, 8 + paddb m2, m3 + +; prefix sum current val + pslldq m3, m4, 1 + paddb m4, m3 + pslldq m3, m4, 2 + paddb m4, m3 + pslldq m3, m4, 4 + paddb m4, m3 + pslldq m3, m4, 8 + paddb m4, m3 + +; last sum + paddb m2, m4 ; current + (A - B) + + paddb xm1, xm2 ; += C + mova [srcq + widthq], xm1 ; store + + pshufb xm1, xm0 ; put last val in all val of xm1 + +%if mmsize == 32 + vextracti128 xm2, m2, 1 ; get second lane of the ymm + paddb xm1, xm2; += C + + mova [srcq + widthq + 16], xm1 ; store + pshufb xm1, xm0 ; put last val in all val of m1 +%endif + + add widthq, mmsize + jl .loop + RET + +%endmacro + +INIT_XMM ssse3 +ADD_GRADIENT_PRED + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_GRADIENT_PRED +%endif diff --git a/libavcodec/x86/lossless_videodsp_init.c b/libavcodec/x86/lossless_videodsp_init.c index 21bbd12bd..6d71f14e7 100644 --- a/libavcodec/x86/lossless_videodsp_init.c +++ b/libavcodec/x86/lossless_videodsp_init.c @@ -25,6 +25,7 @@ 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, @@ -37,9 +38,14 @@ 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_sse4(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, @@ -106,13 +112,17 @@ void ff_llviddsp_init_x86(LLVidDSPContext *c) 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_SSE4(cpu_flags)) { - c->add_left_pred_int16 = ff_add_left_pred_int16_sse4; + 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/libavcodec/x86/mpegvideodsp.c b/libavcodec/x86/mpegvideodsp.c index e0498f384..6009b64e0 100644 --- a/libavcodec/x86/mpegvideodsp.c +++ b/libavcodec/x86/mpegvideodsp.c @@ -52,8 +52,9 @@ static void gmc_mmx(uint8_t *dst, uint8_t *src, 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 || - (unsigned) iy >= height - h; + 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)) | diff --git a/libavcodec/x86/rv40dsp.asm b/libavcodec/x86/rv40dsp.asm index d0c3af0f8..bcad1aee8 100644 --- a/libavcodec/x86/rv40dsp.asm +++ b/libavcodec/x86/rv40dsp.asm @@ -25,7 +25,6 @@ SECTION_RODATA -align 16 pw_1024: times 8 dw 1 << (16 - 6) ; pw_1024 sixtap_filter_hb_m: times 8 db 1, -5 diff --git a/libavcodec/x86/utvideodsp.asm b/libavcodec/x86/utvideodsp.asm index e44c1ea47..b799c44b6 100644 --- a/libavcodec/x86/utvideodsp.asm +++ b/libavcodec/x86/utvideodsp.asm @@ -1,6 +1,7 @@ ;****************************************************************************** ;* SIMD-optimized UTVideo functions ;* Copyright (c) 2017 Paul B Mahol +;* Copyright (c) 2017 Jokyo Images ;* ;* This file is part of FFmpeg. ;* @@ -23,17 +24,18 @@ SECTION_RODATA -pb_128: times 16 db 128 -pw_512: times 8 dw 512 -pw_1023: times 8 dw 1023 +cextern pb_80 +cextern pw_512 +cextern pw_1023 SECTION .text -INIT_XMM sse2 - +;------------------------------------------------------------------------------------------- ; void restore_rgb_planes(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) +;------------------------------------------------------------------------------------------- +%macro RESTORE_RGB_PLANES 0 cglobal restore_rgb_planes, 7 + ARCH_X86_64, 7 + ARCH_X86_64 * 2, 4, src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, w, h, x movsxdifnidn wq, wd add src_rq, wq @@ -46,7 +48,7 @@ DEFINE_ARGS src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, x %define wq r6m %define hd r7mp %endif - mova m3, [pb_128] + mova m3, [pb_80] .nextrow: mov xq, wq @@ -68,7 +70,22 @@ DEFINE_ARGS src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, x sub hd, 1 jg .nextrow REP_RET +%endmacro +INIT_XMM sse2 +RESTORE_RGB_PLANES + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +RESTORE_RGB_PLANES +%endif + +;------------------------------------------------------------------------------------------- +; void restore_rgb_planes10(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) +;------------------------------------------------------------------------------------------- +%macro RESTORE_RGB_PLANES10 0 cglobal restore_rgb_planes10, 7 + ARCH_X86_64, 7 + ARCH_X86_64 * 2, 5, src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, w, h, x shl wd, 1 shl linesize_rq, 1 @@ -109,3 +126,12 @@ DEFINE_ARGS src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, x sub hd, 1 jg .nextrow REP_RET +%endmacro + +INIT_XMM sse2 +RESTORE_RGB_PLANES10 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +RESTORE_RGB_PLANES10 +%endif diff --git a/libavcodec/x86/utvideodsp_init.c b/libavcodec/x86/utvideodsp_init.c index f8b2a9b07..2b436c6c5 100644 --- a/libavcodec/x86/utvideodsp_init.c +++ b/libavcodec/x86/utvideodsp_init.c @@ -28,9 +28,16 @@ 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) { @@ -40,4 +47,8 @@ av_cold void ff_utvideodsp_init_x86(UTVideoDSPContext *c) 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/libavcodec/x86/vp8dsp.asm b/libavcodec/x86/vp8dsp.asm index e303b8029..75de5690a 100644 --- a/libavcodec/x86/vp8dsp.asm +++ b/libavcodec/x86/vp8dsp.asm @@ -664,6 +664,37 @@ INIT_XMM sse2 FILTER_V 8 %macro FILTER_BILINEAR 1 +%if cpuflag(ssse3) +cglobal put_vp8_bilinear%1_v, 7, 7, 5, dst, dststride, src, srcstride, height, picreg, my + shl myd, 4 +%ifdef PIC + lea picregq, [bilinear_filter_vb_m] +%endif + pxor m4, m4 + mova m3, [bilinear_filter_vb+myq-16] +.nextrow: + movh m0, [srcq+srcstrideq*0] + movh m1, [srcq+srcstrideq*1] + movh m2, [srcq+srcstrideq*2] + punpcklbw m0, m1 + punpcklbw m1, m2 + pmaddubsw m0, m3 + pmaddubsw m1, m3 + psraw m0, 2 + psraw m1, 2 + pavgw m0, m4 + pavgw m1, m4 +%if mmsize==8 + packuswb m0, m0 + packuswb m1, m1 + movh [dstq+dststrideq*0], m0 + movh [dstq+dststrideq*1], m1 +%else + packuswb m0, m1 + movh [dstq+dststrideq*0], m0 + movhps [dstq+dststrideq*1], m0 +%endif +%else ; cpuflag(ssse3) cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, picreg, my shl myd, 4 %ifdef PIC @@ -701,6 +732,7 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, p movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 %endif +%endif ; cpuflag(ssse3) lea dstq, [dstq+dststrideq*2] lea srcq, [srcq+srcstrideq*2] @@ -708,6 +740,37 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, p jg .nextrow REP_RET +%if cpuflag(ssse3) +cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 5, dst, dststride, src, srcstride, height, mx, picreg + shl mxd, 4 +%ifdef PIC + lea picregq, [bilinear_filter_vb_m] +%endif + pxor m4, m4 + mova m2, [filter_h2_shuf] + mova m3, [bilinear_filter_vb+mxq-16] +.nextrow: + movu m0, [srcq+srcstrideq*0] + movu m1, [srcq+srcstrideq*1] + pshufb m0, m2 + pshufb m1, m2 + pmaddubsw m0, m3 + pmaddubsw m1, m3 + psraw m0, 2 + psraw m1, 2 + pavgw m0, m4 + pavgw m1, m4 +%if mmsize==8 + packuswb m0, m0 + packuswb m1, m1 + movh [dstq+dststrideq*0], m0 + movh [dstq+dststrideq*1], m1 +%else + packuswb m0, m1 + movh [dstq+dststrideq*0], m0 + movhps [dstq+dststrideq*1], m0 +%endif +%else ; cpuflag(ssse3) cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 7, dst, dststride, src, srcstride, height, mx, picreg shl mxd, 4 %ifdef PIC @@ -746,6 +809,7 @@ cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 7, dst, dststride, src, srcstride movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 %endif +%endif ; cpuflag(ssse3) lea dstq, [dstq+dststrideq*2] lea srcq, [srcq+srcstrideq*2] @@ -758,85 +822,10 @@ INIT_MMX mmxext FILTER_BILINEAR 4 INIT_XMM sse2 FILTER_BILINEAR 8 - -%macro FILTER_BILINEAR_SSSE3 1 -cglobal put_vp8_bilinear%1_v, 7, 7, 5, dst, dststride, src, srcstride, height, picreg, my - shl myd, 4 -%ifdef PIC - lea picregq, [bilinear_filter_vb_m] -%endif - pxor m4, m4 - mova m3, [bilinear_filter_vb+myq-16] -.nextrow: - movh m0, [srcq+srcstrideq*0] - movh m1, [srcq+srcstrideq*1] - movh m2, [srcq+srcstrideq*2] - punpcklbw m0, m1 - punpcklbw m1, m2 - pmaddubsw m0, m3 - pmaddubsw m1, m3 - psraw m0, 2 - psraw m1, 2 - pavgw m0, m4 - pavgw m1, m4 -%if mmsize==8 - packuswb m0, m0 - packuswb m1, m1 - movh [dstq+dststrideq*0], m0 - movh [dstq+dststrideq*1], m1 -%else - packuswb m0, m1 - movh [dstq+dststrideq*0], m0 - movhps [dstq+dststrideq*1], m0 -%endif - - lea dstq, [dstq+dststrideq*2] - lea srcq, [srcq+srcstrideq*2] - sub heightd, 2 - jg .nextrow - REP_RET - -cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 5, dst, dststride, src, srcstride, height, mx, picreg - shl mxd, 4 -%ifdef PIC - lea picregq, [bilinear_filter_vb_m] -%endif - pxor m4, m4 - mova m2, [filter_h2_shuf] - mova m3, [bilinear_filter_vb+mxq-16] -.nextrow: - movu m0, [srcq+srcstrideq*0] - movu m1, [srcq+srcstrideq*1] - pshufb m0, m2 - pshufb m1, m2 - pmaddubsw m0, m3 - pmaddubsw m1, m3 - psraw m0, 2 - psraw m1, 2 - pavgw m0, m4 - pavgw m1, m4 -%if mmsize==8 - packuswb m0, m0 - packuswb m1, m1 - movh [dstq+dststrideq*0], m0 - movh [dstq+dststrideq*1], m1 -%else - packuswb m0, m1 - movh [dstq+dststrideq*0], m0 - movhps [dstq+dststrideq*1], m0 -%endif - - lea dstq, [dstq+dststrideq*2] - lea srcq, [srcq+srcstrideq*2] - sub heightd, 2 - jg .nextrow - REP_RET -%endmacro - INIT_MMX ssse3 -FILTER_BILINEAR_SSSE3 4 +FILTER_BILINEAR 4 INIT_XMM ssse3 -FILTER_BILINEAR_SSSE3 8 +FILTER_BILINEAR 8 INIT_MMX mmx cglobal put_vp8_pixels8, 5, 5, 0, dst, dststride, src, srcstride, height diff --git a/libavcodec/xan.c b/libavcodec/xan.c index 4c01c0013..1ccf16484 100644 --- a/libavcodec/xan.c +++ b/libavcodec/xan.c @@ -131,7 +131,10 @@ static int xan_huffman_decode(uint8_t *dest, int dest_len, return ret; while (val != 0x16) { - unsigned idx = val - 0x17 + get_bits1(&gb) * byte; + unsigned idx; + if (get_bits_left(&gb) < 1) + return AVERROR_INVALIDDATA; + idx = val - 0x17 + get_bits1(&gb) * byte; if (idx >= 2 * byte) return AVERROR_INVALIDDATA; val = src[idx]; @@ -263,7 +266,7 @@ static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame, prevframe_index = (y + motion_y) * stride + x + motion_x; prevframe_x = x + motion_x; - if (prev_palette_plane == palette_plane && FFABS(curframe_index - prevframe_index) < pixel_count) { + if (prev_palette_plane == palette_plane && FFABS(motion_x + width*motion_y) < pixel_count) { avpriv_request_sample(s->avctx, "Overlapping copy"); return ; } diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c index b09dc41eb..f91d2e393 100644 --- a/libavcodec/zmbv.c +++ b/libavcodec/zmbv.c @@ -539,6 +539,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac } else { frame->key_frame = 0; frame->pict_type = AV_PICTURE_TYPE_P; + if (c->decomp_len < 2LL * ((c->width + c->bw - 1) / c->bw) * ((c->height + c->bh - 1) / c->bh)) + return AVERROR_INVALIDDATA; if (c->decomp_len) c->decode_xor(c); } diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h index cd41d965f..1ed8c8219 100644 --- a/libavdevice/alsa.h +++ b/libavdevice/alsa.h @@ -43,7 +43,7 @@ typedef void (*ff_reorder_func)(const void *, void *, int); -#define ALSA_BUFFER_SIZE_MAX 65536 +#define ALSA_BUFFER_SIZE_MAX 131072 typedef struct AlsaData { AVClass *class; diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c index 01c46924d..72e1b6788 100644 --- a/libavdevice/avdevice.c +++ b/libavdevice/avdevice.c @@ -135,9 +135,9 @@ int avdevice_app_to_dev_control_message(struct AVFormatContext *s, enum AVAppToD int avdevice_dev_to_app_control_message(struct AVFormatContext *s, enum AVDevToAppMessageType type, void *data, size_t data_size) { - if (!av_format_get_control_message_cb(s)) + if (!s->control_message_cb) return AVERROR(ENOSYS); - return av_format_get_control_message_cb(s)(s, type, data, data_size); + return s->control_message_cb(s, type, data, data_size); } int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s, diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index 2bd63ac82..6ef2c529f 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -75,7 +75,6 @@ static char *dup_wchar_to_utf8(wchar_t *w) #define DECKLINK_STR OLECHAR * #define DECKLINK_STRDUP dup_wchar_to_utf8 #define DECKLINK_FREE(s) SysFreeString(s) -#define DECKLINK_BOOL BOOL #elif defined(__APPLE__) static char *dup_cfstring_to_utf8(CFStringRef w) { @@ -86,13 +85,11 @@ static char *dup_cfstring_to_utf8(CFStringRef w) #define DECKLINK_STR const __CFString * #define DECKLINK_STRDUP dup_cfstring_to_utf8 #define DECKLINK_FREE(s) CFRelease(s) -#define DECKLINK_BOOL bool #else #define DECKLINK_STR const char * #define DECKLINK_STRDUP av_strdup /* free() is needed for a string returned by the DeckLink SDL. */ #define DECKLINK_FREE(s) free((void *) s) -#define DECKLINK_BOOL bool #endif HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName) @@ -148,23 +145,12 @@ static DECKLINK_BOOL field_order_eq(enum AVFieldOrder field_order, BMDFieldDomin return false; } -int ff_decklink_set_format(AVFormatContext *avctx, - int width, int height, - int tb_num, int tb_den, - enum AVFieldOrder field_order, - decklink_direction_t direction, int num) -{ +int ff_decklink_set_configs(AVFormatContext *avctx, + decklink_direction_t direction) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; - BMDDisplayModeSupport support; - IDeckLinkDisplayModeIterator *itermode; - IDeckLinkDisplayMode *mode; - int i = 1; HRESULT res; - av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n", - width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)"); - if (ctx->duplex_mode) { DECKLINK_BOOL duplex_supported = false; @@ -181,7 +167,6 @@ int ff_decklink_set_format(AVFormatContext *avctx, av_log(avctx, AV_LOG_WARNING, "Unable to set duplex mode, because it is not supported.\n"); } } - if (direction == DIRECTION_IN) { int ret; ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection); @@ -190,6 +175,28 @@ int ff_decklink_set_format(AVFormatContext *avctx, ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection); if (ret < 0) return ret; + } + return 0; +} + +int ff_decklink_set_format(AVFormatContext *avctx, + int width, int height, + int tb_num, int tb_den, + enum AVFieldOrder field_order, + decklink_direction_t direction, int num) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; + BMDDisplayModeSupport support; + IDeckLinkDisplayModeIterator *itermode; + IDeckLinkDisplayMode *mode; + int i = 1; + HRESULT res; + + av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n", + width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)"); + + if (direction == DIRECTION_IN) { res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 6b2525fb5..57ee7d1d6 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -28,6 +28,12 @@ #include "libavutil/thread.h" #include "decklink_common_c.h" +#ifdef _WIN32 +#define DECKLINK_BOOL BOOL +#else +#define DECKLINK_BOOL bool +#endif + class decklink_output_callback; class decklink_input_callback; @@ -95,8 +101,10 @@ struct decklink_ctx { pthread_mutex_t mutex; pthread_cond_t cond; int frames_buffer_available_spots; + int autodetect; int channels; + int audio_depth; }; typedef enum { DIRECTION_IN, DIRECTION_OUT} decklink_direction_t; @@ -133,6 +141,7 @@ static const BMDVideoConnection decklink_video_connection_map[] = { }; HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName); +int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t direction); int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0); int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); int ff_decklink_list_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list, int show_inputs, int show_outputs); diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h index 5616ab32f..368ac259e 100644 --- a/libavdevice/decklink_common_c.h +++ b/libavdevice/decklink_common_c.h @@ -42,6 +42,7 @@ struct decklink_cctx { double preroll; int v210; int audio_channels; + int audio_depth; int duplex_mode; DecklinkPtsSource audio_pts_source; DecklinkPtsSource video_pts_source; diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index d9ac01ac9..94dae2600 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -36,6 +36,7 @@ extern "C" { #include "libavutil/avutil.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "libavutil/time.h" #include "libavutil/mathematics.h" #include "libavutil/reverse.h" @@ -49,6 +50,7 @@ extern "C" { #include "decklink_dec.h" #define MAX_WIDTH_VANC 1920 +const BMDDisplayMode AUTODETECT_DEFAULT_MODE = bmdModeNTSC; typedef struct VANCLineNumber { BMDDisplayMode mode; @@ -262,8 +264,8 @@ static uint8_t* teletext_data_unit_from_ancillary_packet(uint16_t *py, uint16_t return tgt; } -uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words, - unsigned &cc_count) +static uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words, + unsigned &cc_count) { size_t i, len = (buf[5] & 0xff) + 6 + 1; uint8_t cdp_sum, rate; @@ -352,8 +354,8 @@ uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words, return cc; } -uint8_t *get_metadata(AVFormatContext *avctx, uint16_t *buf, size_t width, - uint8_t *tgt, size_t tgt_size, AVPacket *pkt) +static uint8_t *get_metadata(AVFormatContext *avctx, uint16_t *buf, size_t width, + uint8_t *tgt, size_t tgt_size, AVPacket *pkt) { decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; uint16_t *max_buf = buf + width; @@ -634,6 +636,15 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( BMDTimeValue frameDuration; int64_t wallclock = 0; + if (ctx->autodetect) { + if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) && + ctx->bmd_mode == bmdModeUnknown) + { + ctx->bmd_mode = AUTODETECT_DEFAULT_MODE; + } + return S_OK; + } + ctx->frameCount++; if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == PTS_SRC_WALLCLOCK) wallclock = av_gettime_relative(); @@ -771,7 +782,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( av_init_packet(&pkt); //hack among hacks - pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->channels * (16 / 8); + pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8); audioFrame->GetBytes(&audioFrameBytes); audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den); pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts); @@ -794,17 +805,56 @@ HRESULT decklink_input_callback::VideoInputFormatChanged( BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags) { + ctx->bmd_mode = mode->GetDisplayMode(); return S_OK; } -static HRESULT decklink_start_input(AVFormatContext *avctx) -{ - struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; +static int decklink_autodetect(struct decklink_cctx *cctx) { struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; + DECKLINK_BOOL autodetect_supported = false; + int i; + + if (ctx->attr->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &autodetect_supported) != S_OK) + return -1; + if (autodetect_supported == false) + return -1; + + ctx->autodetect = 1; + ctx->bmd_mode = bmdModeUnknown; + if (ctx->dli->EnableVideoInput(AUTODETECT_DEFAULT_MODE, + bmdFormat8BitYUV, + bmdVideoInputEnableFormatDetection) != S_OK) { + return -1; + } + + if (ctx->dli->StartStreams() != S_OK) { + return -1; + } + + // 1 second timeout + for (i = 0; i < 10; i++) { + av_usleep(100000); + /* Sometimes VideoInputFrameArrived is called without the + * bmdFrameHasNoInputSource flag before VideoInputFormatChanged. + * So don't break for bmd_mode == AUTODETECT_DEFAULT_MODE. */ + if (ctx->bmd_mode != bmdModeUnknown && + ctx->bmd_mode != AUTODETECT_DEFAULT_MODE) + break; + } + + ctx->dli->PauseStreams(); + ctx->dli->FlushStreams(); + ctx->autodetect = 0; + if (ctx->bmd_mode != bmdModeUnknown) { + cctx->format_code = (char *)av_mallocz(5); + if (!cctx->format_code) + return -1; + AV_WB32(cctx->format_code, ctx->bmd_mode); + return 0; + } else { + return -1; + } - ctx->input_callback = new decklink_input_callback(avctx); - ctx->dli->SetCallback(ctx->input_callback); - return ctx->dli->StartStreams(); } extern "C" { @@ -854,6 +904,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) ctx->audio_pts_source = cctx->audio_pts_source; ctx->video_pts_source = cctx->video_pts_source; ctx->draw_bars = cctx->draw_bars; + ctx->audio_depth = cctx->audio_depth; cctx->ctx = ctx; /* Check audio channel option for valid values: 2, 8 or 16 */ @@ -867,6 +918,16 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) return AVERROR(EINVAL); } + /* Check audio bit depth option for valid values: 16 or 32 */ + switch (cctx->audio_depth) { + case 16: + case 32: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Value for audio bit depth option must be either 16 or 32\n"); + return AVERROR(EINVAL); + } + /* List available devices. */ if (ctx->list_devices) { ff_decklink_list_devices_legacy(avctx, 1, 0); @@ -905,13 +966,28 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; } - if (mode_num > 0 || cctx->format_code) { - if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n", - mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname); + if (ff_decklink_set_configs(avctx, DIRECTION_IN) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set input configuration\n"); + ret = AVERROR(EIO); + goto error; + } + + ctx->input_callback = new decklink_input_callback(avctx); + ctx->dli->SetCallback(ctx->input_callback); + + if (mode_num == 0 && !cctx->format_code) { + if (decklink_autodetect(cctx) < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot Autodetect input stream or No signal\n"); ret = AVERROR(EIO); goto error; } + av_log(avctx, AV_LOG_INFO, "Autodetected the input mode\n"); + } + if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n", + mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname); + ret = AVERROR(EIO); + goto error; } #if !CONFIG_LIBZVBI @@ -930,7 +1006,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; } st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; - st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codecpar->codec_id = cctx->audio_depth == 32 ? AV_CODEC_ID_PCM_S32LE : AV_CODEC_ID_PCM_S16LE; st->codecpar->sample_rate = bmdAudioSampleRate48kHz; st->codecpar->channels = cctx->audio_channels; avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ @@ -948,7 +1024,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) st->time_base.den = ctx->bmd_tb_den; st->time_base.num = ctx->bmd_tb_num; - av_stream_set_r_frame_rate(st, av_make_q(st->time_base.den, st->time_base.num)); + st->r_frame_rate = av_make_q(st->time_base.den, st->time_base.num); switch((BMDPixelFormat)cctx->raw_format) { case bmdFormat8BitYUV: @@ -1021,7 +1097,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) } av_log(avctx, AV_LOG_VERBOSE, "Using %d input audio channels\n", ctx->audio_st->codecpar->channels); - result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, ctx->audio_st->codecpar->channels); + result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz, cctx->audio_depth == 32 ? bmdAudioSampleType32bitInteger : bmdAudioSampleType16bitInteger, ctx->audio_st->codecpar->channels); if (result != S_OK) { av_log(avctx, AV_LOG_ERROR, "Cannot enable audio input\n"); @@ -1041,7 +1117,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) avpacket_queue_init (avctx, &ctx->queue); - if (decklink_start_input (avctx) != S_OK) { + if (ctx->dli->StartStreams() != S_OK) { av_log(avctx, AV_LOG_ERROR, "Cannot start input stream\n"); ret = AVERROR(EIO); goto error; diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c index 1127d23ad..1c6d82694 100644 --- a/libavdevice/decklink_dec_c.c +++ b/libavdevice/decklink_dec_c.c @@ -72,6 +72,7 @@ static const AVOption options[] = { { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, "pts_source"}, { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC }, { "queue_size", "input queue buffer size", OFFSET(queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC }, + { "audio_depth", "audio bitdepth (16 or 32)", OFFSET(audio_depth), AV_OPT_TYPE_INT, { .i64 = 16}, 16, 32, DEC }, { NULL }, }; diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index 81df563b3..c06ca4668 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -162,6 +162,10 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) return -1; } + if (ff_decklink_set_configs(avctx, DIRECTION_OUT) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set output configuration\n"); + return -1; + } if (ff_decklink_set_format(avctx, c->width, c->height, st->time_base.num, st->time_base.den, c->field_order)) { av_log(avctx, AV_LOG_ERROR, "Unsupported video size, framerate or field order!" diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c index 87f501203..ff2ef3b16 100644 --- a/libavdevice/gdigrab.c +++ b/libavdevice/gdigrab.c @@ -235,7 +235,9 @@ gdigrab_read_header(AVFormatContext *s1) AVStream *st = NULL; int bpp; + int horzres; int vertres; + int desktophorzres; int desktopvertres; RECT virtual_rect; RECT clip_rect; @@ -279,11 +281,13 @@ gdigrab_read_header(AVFormatContext *s1) GetClientRect(hwnd, &virtual_rect); } else { /* desktop -- get the right height and width for scaling DPI */ + horzres = GetDeviceCaps(source_hdc, HORZRES); vertres = GetDeviceCaps(source_hdc, VERTRES); + desktophorzres = GetDeviceCaps(source_hdc, DESKTOPHORZRES); desktopvertres = GetDeviceCaps(source_hdc, DESKTOPVERTRES); virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); - virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktopvertres / vertres; + virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktophorzres / horzres; virtual_rect.bottom = (virtual_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN)) * desktopvertres / vertres; } @@ -447,7 +451,9 @@ static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab) POINT pos; RECT clip_rect = gdigrab->clip_rect; HWND hwnd = gdigrab->hwnd; + int horzres = GetDeviceCaps(gdigrab->source_hdc, HORZRES); int vertres = GetDeviceCaps(gdigrab->source_hdc, VERTRES); + int desktophorzres = GetDeviceCaps(gdigrab->source_hdc, DESKTOPHORZRES); int desktopvertres = GetDeviceCaps(gdigrab->source_hdc, DESKTOPVERTRES); info.hbmMask = NULL; info.hbmColor = NULL; @@ -483,7 +489,7 @@ static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab) } //that would keep the correct location of mouse with hidpi screens - pos.x = pos.x * desktopvertres / vertres; + pos.x = pos.x * desktophorzres / horzres; pos.y = pos.y * desktopvertres / vertres; av_log(s1, AV_LOG_DEBUG, "Cursor pos (%li,%li) -> (%li,%li)\n", diff --git a/libavdevice/jack.c b/libavdevice/jack.c index 076078ce6..e35a4a815 100644 --- a/libavdevice/jack.c +++ b/libavdevice/jack.c @@ -94,13 +94,9 @@ static int process_callback(jack_nframes_t nframes, void *arg) /* Copy and interleave audio data from the JACK buffer into the packet */ for (i = 0; i < self->nports; i++) { - #if HAVE_JACK_PORT_GET_LATENCY_RANGE jack_latency_range_t range; jack_port_get_latency_range(self->ports[i], JackCaptureLatency, &range); latency += range.max; - #else - latency += jack_port_get_total_latency(self->client, self->ports[i]); - #endif buffer = jack_port_get_buffer(self->ports[i], self->buffer_size); for (j = 0; j < self->buffer_size; j++) pkt_data[j * self->nports + i] = buffer[j]; diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c index ede391f4d..5273717e6 100644 --- a/libavdevice/lavfi.c +++ b/libavdevice/lavfi.c @@ -38,7 +38,6 @@ #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavfilter/avfilter.h" -#include "libavfilter/avfiltergraph.h" #include "libavfilter/buffersink.h" #include "libavformat/avio_internal.h" #include "libavformat/internal.h" @@ -121,7 +120,7 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) { LavfiContext *lavfi = avctx->priv_data; AVFilterInOut *input_links = NULL, *output_links = NULL, *inout; - AVFilter *buffersink, *abuffersink; + const AVFilter *buffersink, *abuffersink; int *pix_fmts = create_all_formats(AV_PIX_FMT_NB); enum AVMediaType type; int ret = 0, i, n; diff --git a/libavdevice/libndi_newtek_dec.c b/libavdevice/libndi_newtek_dec.c index 8cbcd9a1d..2f14f4b03 100644 --- a/libavdevice/libndi_newtek_dec.c +++ b/libavdevice/libndi_newtek_dec.c @@ -189,7 +189,7 @@ static int ndi_create_video_stream(AVFormatContext *avctx, NDIlib_video_frame_t } st->time_base = NDI_TIME_BASE_Q; - av_stream_set_r_frame_rate(st, av_make_q(v->frame_rate_N, v->frame_rate_D)); + st->r_frame_rate = av_make_q(v->frame_rate_N, v->frame_rate_D); tmp = av_mul_q(av_d2q(v->picture_aspect_ratio, INT_MAX), (AVRational){v->yres, v->xres}); av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, tmp.num, tmp.den, 1000); diff --git a/libavdevice/oss.c b/libavdevice/oss.c index d74112825..d92cde331 100644 --- a/libavdevice/oss.c +++ b/libavdevice/oss.c @@ -23,17 +23,12 @@ #include -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - #if HAVE_UNISTD_H #include #endif #include #include +#include #include "libavutil/log.h" diff --git a/libavdevice/oss_dec.c b/libavdevice/oss_dec.c index 9f748f2bc..6fef96a45 100644 --- a/libavdevice/oss_dec.c +++ b/libavdevice/oss_dec.c @@ -23,17 +23,12 @@ #include -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - #if HAVE_UNISTD_H #include #endif #include #include +#include #include "libavutil/internal.h" #include "libavutil/opt.h" diff --git a/libavdevice/oss_enc.c b/libavdevice/oss_enc.c index 2268b4cfe..e7a7b6d40 100644 --- a/libavdevice/oss_enc.c +++ b/libavdevice/oss_enc.c @@ -21,17 +21,12 @@ #include "config.h" -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - #if HAVE_UNISTD_H #include #endif #include #include +#include #include "libavutil/internal.h" diff --git a/libavdevice/tests/.gitignore b/libavdevice/tests/.gitignore new file mode 100644 index 000000000..b4a2281a7 --- /dev/null +++ b/libavdevice/tests/.gitignore @@ -0,0 +1 @@ +/timefilter diff --git a/libavdevice/version.h b/libavdevice/version.h index 9d900877a..364404d65 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -27,8 +27,8 @@ #include "libavutil/version.h" -#define LIBAVDEVICE_VERSION_MAJOR 57 -#define LIBAVDEVICE_VERSION_MINOR 10 +#define LIBAVDEVICE_VERSION_MAJOR 58 +#define LIBAVDEVICE_VERSION_MINOR 0 #define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ diff --git a/libavfilter/Makefile b/libavfilter/Makefile index d2f0495f3..ef4729dd3 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -2,7 +2,6 @@ NAME = avfilter DESC = FFmpeg audio/video filtering library HEADERS = avfilter.h \ - avfiltergraph.h \ buffersink.h \ buffersrc.h \ version.h \ @@ -20,15 +19,18 @@ OBJS = allfilters.o \ framequeue.o \ graphdump.o \ graphparser.o \ - opencl_allkernels.o \ transform.o \ video.o \ OBJS-$(HAVE_THREADS) += pthread.o +# subsystems +OBJS-$(CONFIG_QSVVPP) += qsvvpp.o + # audio filters OBJS-$(CONFIG_ABENCH_FILTER) += f_bench.o OBJS-$(CONFIG_ACOMPRESSOR_FILTER) += af_sidechaincompress.o +OBJS-$(CONFIG_ACONTRAST_FILTER) += af_acontrast.o OBJS-$(CONFIG_ACOPY_FILTER) += af_acopy.o OBJS-$(CONFIG_ACROSSFADE_FILTER) += af_afade.o OBJS-$(CONFIG_ACRUSHER_FILTER) += af_acrusher.o @@ -41,6 +43,7 @@ OBJS-$(CONFIG_AFFTFILT_FILTER) += af_afftfilt.o OBJS-$(CONFIG_AFIR_FILTER) += af_afir.o OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o OBJS-$(CONFIG_AGATE_FILTER) += af_agate.o +OBJS-$(CONFIG_AIIR_FILTER) += af_aiir.o OBJS-$(CONFIG_AINTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_ALIMITER_FILTER) += af_alimiter.o OBJS-$(CONFIG_ALLPASS_FILTER) += af_biquads.o @@ -99,6 +102,8 @@ OBJS-$(CONFIG_JOIN_FILTER) += af_join.o OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o OBJS-$(CONFIG_LOUDNORM_FILTER) += af_loudnorm.o ebur128.o OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o +OBJS-$(CONFIG_LV2_FILTER) += af_lv2.o +OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o OBJS-$(CONFIG_PAN_FILTER) += af_pan.o OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o @@ -122,6 +127,7 @@ OBJS-$(CONFIG_AEVALSRC_FILTER) += aeval.o OBJS-$(CONFIG_ANOISESRC_FILTER) += asrc_anoisesrc.o OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o +OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o @@ -161,6 +167,7 @@ OBJS-$(CONFIG_DATASCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_DCTDNOIZ_FILTER) += vf_dctdnoiz.o OBJS-$(CONFIG_DEBAND_FILTER) += vf_deband.o OBJS-$(CONFIG_DECIMATE_FILTER) += vf_decimate.o +OBJS-$(CONFIG_DECONVOLVE_FILTER) += vf_convolve.o framesync.o OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o @@ -179,6 +186,7 @@ OBJS-$(CONFIG_DRAWGRID_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o +OBJS-$(CONFIG_ENTROPY_FILTER) += vf_entropy.o OBJS-$(CONFIG_EQ_FILTER) += vf_eq.o OBJS-$(CONFIG_EROSION_FILTER) += vf_neighbor.o OBJS-$(CONFIG_EXTRACTPLANES_FILTER) += vf_extractplanes.o @@ -188,6 +196,7 @@ OBJS-$(CONFIG_FIELD_FILTER) += vf_field.o OBJS-$(CONFIG_FIELDHINT_FILTER) += vf_fieldhint.o OBJS-$(CONFIG_FIELDMATCH_FILTER) += vf_fieldmatch.o OBJS-$(CONFIG_FIELDORDER_FILTER) += vf_fieldorder.o +OBJS-$(CONFIG_FILLBORDERS_FILTER) += vf_fillborders.o OBJS-$(CONFIG_FIND_RECT_FILTER) += vf_find_rect.o lavfutils.o OBJS-$(CONFIG_FLOODFILL_FILTER) += vf_floodfill.o OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o @@ -237,18 +246,22 @@ OBJS-$(CONFIG_MESTIMATE_FILTER) += vf_mestimate.o motion_estimation OBJS-$(CONFIG_METADATA_FILTER) += f_metadata.o OBJS-$(CONFIG_MIDEQUALIZER_FILTER) += vf_midequalizer.o framesync.o OBJS-$(CONFIG_MINTERPOLATE_FILTER) += vf_minterpolate.o motion_estimation.o +OBJS-$(CONFIG_MIX_FILTER) += vf_mix.o OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o OBJS-$(CONFIG_NEGATE_FILTER) += vf_lut.o OBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o OBJS-$(CONFIG_NNEDI_FILTER) += vf_nnedi.o OBJS-$(CONFIG_NOFORMAT_FILTER) += vf_format.o OBJS-$(CONFIG_NOISE_FILTER) += vf_noise.o +OBJS-$(CONFIG_NORMALIZE_FILTER) += vf_normalize.o OBJS-$(CONFIG_NULL_FILTER) += vf_null.o OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o -OBJS-$(CONFIG_OPENCL) += deshake_opencl.o unsharp_opencl.o OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o framesync.o +OBJS-$(CONFIG_OVERLAY_OPENCL_FILTER) += vf_overlay_opencl.o opencl.o \ + opencl/overlay.o framesync.o +OBJS-$(CONFIG_OVERLAY_QSV_FILTER) += vf_overlay_qsv.o OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o @@ -262,6 +275,7 @@ OBJS-$(CONFIG_PP_FILTER) += vf_pp.o OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o OBJS-$(CONFIG_PREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_PREWITT_FILTER) += vf_convolution.o +OBJS-$(CONFIG_PROGRAM_OPENCL_FILTER) += vf_program_opencl.o opencl.o framesync.o OBJS-$(CONFIG_PSEUDOCOLOR_FILTER) += vf_pseudocolor.o OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o framesync.o OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o @@ -291,6 +305,7 @@ OBJS-$(CONFIG_SEPARATEFIELDS_FILTER) += vf_separatefields.o OBJS-$(CONFIG_SETDAR_FILTER) += vf_aspect.o OBJS-$(CONFIG_SETFIELD_FILTER) += vf_setfield.o OBJS-$(CONFIG_SETPTS_FILTER) += setpts.o +OBJS-$(CONFIG_SETRANGE_FILTER) += vf_setparams.o OBJS-$(CONFIG_SETSAR_FILTER) += vf_aspect.o OBJS-$(CONFIG_SETTB_FILTER) += settb.o OBJS-$(CONFIG_SHOWINFO_FILTER) += vf_showinfo.o @@ -324,6 +339,8 @@ OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o OBJS-$(CONFIG_TRIM_FILTER) += trim.o OBJS-$(CONFIG_UNPREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o +OBJS-$(CONFIG_UNSHARP_OPENCL_FILTER) += vf_unsharp_opencl.o opencl.o \ + opencl/unsharp.o OBJS-$(CONFIG_USPP_FILTER) += vf_uspp.o OBJS-$(CONFIG_VAGUEDENOISER_FILTER) += vf_vaguedenoiser.o OBJS-$(CONFIG_VECTORSCOPE_FILTER) += vf_vectorscope.o @@ -332,6 +349,7 @@ OBJS-$(CONFIG_VIDSTABDETECT_FILTER) += vidstabutils.o vf_vidstabdetect. OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += vidstabutils.o vf_vidstabtransform.o OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o +OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o OBJS-$(CONFIG_VSTACK_FILTER) += vf_stack.o framesync.o OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o OBJS-$(CONFIG_WAVEFORM_FILTER) += vf_waveform.o @@ -353,6 +371,7 @@ OBJS-$(CONFIG_LIFE_FILTER) += vsrc_life.o OBJS-$(CONFIG_MANDELBROT_FILTER) += vsrc_mandelbrot.o OBJS-$(CONFIG_MPTESTSRC_FILTER) += vsrc_mptestsrc.o OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_OPENCLSRC_FILTER) += vf_program_opencl.o opencl.o OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o @@ -386,10 +405,12 @@ OBJS-$(CONFIG_MOVIE_FILTER) += src_movie.o SLIBOBJS-$(HAVE_GNU_WINDRES) += avfilterres.o SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h -SKIPHEADERS-$(CONFIG_OPENCL) += opencl_internal.h deshake_opencl_kernel.h unsharp_opencl_kernel.h OBJS-$(CONFIG_SHARED) += log2_tab.o +SKIPHEADERS-$(CONFIG_QSVVPP) += qsvvpp.h +SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h + TOOLS = graph2dot TESTPROGS = drawutils filtfmts formats integral @@ -397,3 +418,9 @@ TOOLS-$(CONFIG_LIBZMQ) += zmqsend clean:: $(RM) $(CLEANSUFFIXES:%=libavfilter/libmpcodecs/%) + +OPENCL = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/opencl/*.cl)) +.SECONDARY: $(OPENCL:.cl=.c) +libavfilter/opencl/%.c: TAG = OPENCL +libavfilter/opencl/%.c: $(SRC_PATH)/libavfilter/opencl/%.cl + $(M)$(SRC_PATH)/tools/cl2c $< $@ diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c new file mode 100644 index 000000000..e08053146 --- /dev/null +++ b/libavfilter/af_acontrast.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2008 Rob Sykes + * 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 "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" + +typedef struct AudioContrastContext { + const AVClass *class; + float contrast; + void (*filter)(void **dst, const void **src, + int nb_samples, int channels, float contrast); +} AudioContrastContext; + +#define OFFSET(x) offsetof(AudioContrastContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption acontrast_options[] = { + { "contrast", "set contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, {.dbl=33}, 0, 100, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(acontrast); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static void filter_flt(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + const float *src = s[0]; + float *dst = d[0]; + int n, c; + + for (n = 0; n < nb_samples; n++) { + for (c = 0; c < channels; c++) { + float d = src[c] * M_PI_2; + + dst[c] = sinf(d + contrast * sinf(d * 4)); + } + + dst += c; + src += c; + } +} + +static void filter_dbl(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + const double *src = s[0]; + double *dst = d[0]; + int n, c; + + for (n = 0; n < nb_samples; n++) { + for (c = 0; c < channels; c++) { + double d = src[c] * M_PI_2; + + dst[c] = sin(d + contrast * sin(d * 4)); + } + + dst += c; + src += c; + } +} + +static void filter_fltp(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + int n, c; + + for (c = 0; c < channels; c++) { + const float *src = s[c]; + float *dst = d[c]; + + for (n = 0; n < nb_samples; n++) { + float d = src[n] * M_PI_2; + + dst[n] = sinf(d + contrast * sinf(d * 4)); + } + } +} + +static void filter_dblp(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + int n, c; + + for (c = 0; c < channels; c++) { + const double *src = s[c]; + double *dst = d[c]; + + for (n = 0; n < nb_samples; n++) { + double d = src[n] * M_PI_2; + + dst[n] = sin(d + contrast * sin(d * 4)); + } + } +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioContrastContext *s = ctx->priv; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; + case AV_SAMPLE_FMT_DBL: s->filter = filter_dbl; break; + case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break; + case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioContrastContext *s = ctx->priv; + AVFrame *out; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + s->filter((void **)out->extended_data, (const void **)in->extended_data, + in->nb_samples, in->channels, s->contrast / 750); + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_acontrast = { + .name = "acontrast", + .description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), + .query_formats = query_formats, + .priv_size = sizeof(AudioContrastContext), + .priv_class = &acontrast_class, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index 983f089c2..d6d81ba7d 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -192,7 +192,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (ctx->is_disabled || !s->delays) return ff_filter_frame(ctx->outputs[0], frame); - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index cfaea3de4..b9ac18d3a 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -279,7 +279,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c index a5b8e3058..e1fa93aff 100644 --- a/libavfilter/af_aemphasis.c +++ b/libavfilter/af_aemphasis.c @@ -96,7 +96,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index 7ad124e88..4d0b31eac 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -282,7 +282,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) if (av_frame_is_writable(buf)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(inlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) return AVERROR(ENOMEM); av_frame_copy_props(out_buf, buf); diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 52755a1fb..7f28e1f77 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -197,8 +197,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) int ch, n, ret, i, j, k; int start = s->start, end = s->end; - av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); + ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); av_frame_free(&frame); + if (ret < 0) + return ret; while (av_audio_fifo_size(s->fifo) >= window_size) { if (!in) { @@ -316,7 +318,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) } av_frame_free(&in); - return ret; + return ret < 0 ? ret : 0; } static int query_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index c4443fdff..668724263 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -105,7 +105,7 @@ static int fir_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) if (out) { float *ptr = (float *)out->extended_data[ch]; - s->fdsp->vector_fmul_scalar(ptr, dst, s->gain * s->wet_gain, FFALIGN(out->nb_samples, 4)); + s->fdsp->vector_fmul_scalar(ptr, dst, s->wet_gain, FFALIGN(out->nb_samples, 4)); emms_c(); } @@ -166,7 +166,6 @@ static int convert_coeffs(AVFilterContext *ctx) { AudioFIRContext *s = ctx->priv; int i, ch, n, N; - float power = 0; s->nb_taps = av_audio_fifo_size(s->fifo[1]); if (s->nb_taps <= 0) @@ -217,13 +216,29 @@ static int convert_coeffs(AVFilterContext *ctx) av_audio_fifo_read(s->fifo[1], (void **)s->in[1]->extended_data, s->nb_taps); + if (s->again) { + float power = 0; + + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { + float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; + + for (i = 0; i < s->nb_taps; i++) + power += FFABS(time[i]); + } + + s->gain = sqrtf(1.f / (ctx->inputs[1]->channels * power)) / (sqrtf(ctx->inputs[1]->channels)); + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { + float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; + + s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4)); + } + } + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; float *block = s->block[ch]; FFTComplex *coeff = s->coeff[ch]; - power += s->fdsp->scalarproduct_float(time, time, s->nb_taps); - for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++) time[i] = 0; @@ -252,7 +267,6 @@ static int convert_coeffs(AVFilterContext *ctx) } av_frame_free(&s->in[1]); - s->gain = s->again ? 1.f / sqrtf(power / ctx->inputs[1]->channels) : 1.f; av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", s->nb_taps); av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", s->nb_partitions); av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", s->part_size); @@ -267,11 +281,13 @@ static int read_ir(AVFilterLink *link, AVFrame *frame) { AVFilterContext *ctx = link->dst; AudioFIRContext *s = ctx->priv; - int nb_taps, max_nb_taps; + int nb_taps, max_nb_taps, ret; - av_audio_fifo_write(s->fifo[1], (void **)frame->extended_data, - frame->nb_samples); + ret = av_audio_fifo_write(s->fifo[1], (void **)frame->extended_data, + frame->nb_samples); av_frame_free(&frame); + if (ret < 0) + return ret; nb_taps = av_audio_fifo_size(s->fifo[1]); max_nb_taps = MAX_IR_DURATION * ctx->outputs[0]->sample_rate; @@ -288,15 +304,18 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) AVFilterContext *ctx = link->dst; AudioFIRContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int ret = 0; + int ret; - av_audio_fifo_write(s->fifo[0], (void **)frame->extended_data, - frame->nb_samples); - if (s->pts == AV_NOPTS_VALUE) + ret = av_audio_fifo_write(s->fifo[0], (void **)frame->extended_data, + frame->nb_samples); + if (ret > 0 && s->pts == AV_NOPTS_VALUE) s->pts = frame->pts; av_frame_free(&frame); + if (ret < 0) + return ret; + if (!s->have_coeffs && s->eof_coeffs) { ret = convert_coeffs(ctx); if (ret < 0) @@ -307,10 +326,10 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) while (av_audio_fifo_size(s->fifo[0]) >= s->part_size) { ret = fir_frame(s, outlink); if (ret < 0) - break; + return ret; } } - return ret; + return 0; } static int request_frame(AVFilterLink *outlink) @@ -334,9 +353,11 @@ static int request_frame(AVFilterLink *outlink) if (!silence) return AVERROR(ENOMEM); - av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data, - silence->nb_samples); + ret = av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data, + silence->nb_samples); av_frame_free(&silence); + if (ret < 0) + return ret; s->need_padding = 0; } diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index 20905ccb1..ba96863a6 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -214,7 +214,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -323,14 +323,13 @@ static int activate(AVFilterContext *ctx) } FF_FILTER_FORWARD_STATUS(ctx->inputs[0], ctx->outputs[0]); FF_FILTER_FORWARD_STATUS(ctx->inputs[1], ctx->outputs[0]); - /* TODO reindent */ - if (ff_outlink_frame_wanted(ctx->outputs[0])) { - if (!av_audio_fifo_size(s->fifo[0])) - ff_inlink_request_frame(ctx->inputs[0]); - if (!av_audio_fifo_size(s->fifo[1])) - ff_inlink_request_frame(ctx->inputs[1]); - } - return 0; + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + if (!av_audio_fifo_size(s->fifo[0])) + ff_inlink_request_frame(ctx->inputs[0]); + if (!av_audio_fifo_size(s->fifo[1])) + ff_inlink_request_frame(ctx->inputs[1]); + } + return 0; } static int scquery_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c new file mode 100644 index 000000000..1f2a568c1 --- /dev/null +++ b/libavfilter/af_aiir.c @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2018 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 + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct ThreadData { + AVFrame *in, *out; +} ThreadData; + +typedef struct Pair { + int a, b; +} Pair; + +typedef struct BiquadContext { + double a0, a1, a2; + double b0, b1, b2; + double i1, i2; + double o1, o2; +} BiquadContext; + +typedef struct IIRChannel { + int nb_ab[2]; + double *ab[2]; + double g; + double *cache[2]; + BiquadContext *biquads; + int clippings; +} IIRChannel; + +typedef struct AudioIIRContext { + const AVClass *class; + char *a_str, *b_str, *g_str; + double dry_gain, wet_gain; + int format; + int process; + int precision; + + IIRChannel *iir; + int channels; + enum AVSampleFormat sample_format; + + int (*iir_channel)(AVFilterContext *ctx, void *arg, int ch, int nb_jobs); +} AudioIIRContext; + +static int query_formats(AVFilterContext *ctx) +{ + AudioIIRContext *s = ctx->priv; + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + sample_fmts[0] = s->sample_format; + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +#define IIR_CH(name, type, min, max, need_clipping) \ +static int iir_ch_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) \ +{ \ + AudioIIRContext *s = ctx->priv; \ + const double ig = s->dry_gain; \ + const double og = s->wet_gain; \ + ThreadData *td = arg; \ + AVFrame *in = td->in, *out = td->out; \ + const type *src = (const type *)in->extended_data[ch]; \ + double *ic = (double *)s->iir[ch].cache[0]; \ + double *oc = (double *)s->iir[ch].cache[1]; \ + const int nb_a = s->iir[ch].nb_ab[0]; \ + const int nb_b = s->iir[ch].nb_ab[1]; \ + const double *a = s->iir[ch].ab[0]; \ + const double *b = s->iir[ch].ab[1]; \ + int *clippings = &s->iir[ch].clippings; \ + type *dst = (type *)out->extended_data[ch]; \ + int n; \ + \ + for (n = 0; n < in->nb_samples; n++) { \ + double sample = 0.; \ + int x; \ + \ + memmove(&ic[1], &ic[0], (nb_b - 1) * sizeof(*ic)); \ + memmove(&oc[1], &oc[0], (nb_a - 1) * sizeof(*oc)); \ + ic[0] = src[n] * ig; \ + for (x = 0; x < nb_b; x++) \ + sample += b[x] * ic[x]; \ + \ + for (x = 1; x < nb_a; x++) \ + sample -= a[x] * oc[x]; \ + \ + oc[0] = sample; \ + sample *= og; \ + if (need_clipping && sample < min) { \ + (*clippings)++; \ + dst[n] = min; \ + } else if (need_clipping && sample > max) { \ + (*clippings)++; \ + dst[n] = max; \ + } else { \ + dst[n] = sample; \ + } \ + } \ + \ + return 0; \ +} + +IIR_CH(s16p, int16_t, INT16_MIN, INT16_MAX, 1) +IIR_CH(s32p, int32_t, INT32_MIN, INT32_MAX, 1) +IIR_CH(fltp, float, -1., 1., 0) +IIR_CH(dblp, double, -1., 1., 0) + +#define SERIAL_IIR_CH(name, type, min, max, need_clipping) \ +static int iir_ch_serial_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) \ +{ \ + AudioIIRContext *s = ctx->priv; \ + const double ig = s->dry_gain; \ + const double og = s->wet_gain; \ + ThreadData *td = arg; \ + AVFrame *in = td->in, *out = td->out; \ + const type *src = (const type *)in->extended_data[ch]; \ + type *dst = (type *)out->extended_data[ch]; \ + IIRChannel *iir = &s->iir[ch]; \ + int *clippings = &iir->clippings; \ + int nb_biquads = (FFMAX(iir->nb_ab[0], iir->nb_ab[1]) + 1) / 2; \ + int n, i; \ + \ + for (i = 0; i < nb_biquads; i++) { \ + const double a1 = -iir->biquads[i].a1; \ + const double a2 = -iir->biquads[i].a2; \ + const double b0 = iir->biquads[i].b0; \ + const double b1 = iir->biquads[i].b1; \ + const double b2 = iir->biquads[i].b2; \ + double i1 = iir->biquads[i].i1; \ + double i2 = iir->biquads[i].i2; \ + double o1 = iir->biquads[i].o1; \ + double o2 = iir->biquads[i].o2; \ + \ + for (n = 0; n < in->nb_samples; n++) { \ + double sample = ig * (i ? dst[n] : src[n]); \ + double o0 = sample * b0 + i1 * b1 + i2 * b2 + o1 * a1 + o2 * a2; \ + \ + i2 = i1; \ + i1 = src[n]; \ + o2 = o1; \ + o1 = o0; \ + o0 *= og; \ + \ + if (need_clipping && o0 < min) { \ + (*clippings)++; \ + dst[n] = min; \ + } else if (need_clipping && o0 > max) { \ + (*clippings)++; \ + dst[n] = max; \ + } else { \ + dst[n] = o0; \ + } \ + } \ + iir->biquads[i].i1 = i1; \ + iir->biquads[i].i2 = i2; \ + iir->biquads[i].o1 = o1; \ + iir->biquads[i].o2 = o2; \ + } \ + \ + return 0; \ +} + +SERIAL_IIR_CH(s16p, int16_t, INT16_MIN, INT16_MAX, 1) +SERIAL_IIR_CH(s32p, int32_t, INT32_MIN, INT32_MAX, 1) +SERIAL_IIR_CH(fltp, float, -1., 1., 0) +SERIAL_IIR_CH(dblp, double, -1., 1., 0) + +static void count_coefficients(char *item_str, int *nb_items) +{ + char *p; + + if (!item_str) + return; + + *nb_items = 1; + for (p = item_str; *p && *p != '|'; p++) { + if (*p == ' ') + (*nb_items)++; + } +} + +static int read_gains(AVFilterContext *ctx, char *item_str, int nb_items) +{ + AudioIIRContext *s = ctx->priv; + char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL; + int i; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < nb_items; i++) { + if (!(arg = av_strtok(p, "|", &saveptr))) + arg = prev_arg; + + if (!arg) { + av_freep(&old_str); + return AVERROR(EINVAL); + } + + p = NULL; + if (sscanf(arg, "%lf", &s->iir[i].g) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid gains supplied: %s\n", arg); + av_freep(&old_str); + return AVERROR(EINVAL); + } + + prev_arg = arg; + } + + av_freep(&old_str); + + return 0; +} + +static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst) +{ + char *p, *arg, *old_str, *saveptr = NULL; + int i; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < nb_items; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + if (sscanf(arg, "%lf", &dst[i]) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); + av_freep(&old_str); + return AVERROR(EINVAL); + } + } + + av_freep(&old_str); + + return 0; +} + +static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst, const char *format) +{ + char *p, *arg, *old_str, *saveptr = NULL; + int i; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < nb_items; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + if (sscanf(arg, format, &dst[i*2], &dst[i*2+1]) != 2) { + av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); + av_freep(&old_str); + return AVERROR(EINVAL); + } + } + + av_freep(&old_str); + + return 0; +} + +static const char *format[] = { "%lf", "%lf %lfi", "%lf %lfr", "%lf %lfd" }; + +static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str, int ab) +{ + AudioIIRContext *s = ctx->priv; + char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL; + int i, ret; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < channels; i++) { + IIRChannel *iir = &s->iir[i]; + + if (!(arg = av_strtok(p, "|", &saveptr))) + arg = prev_arg; + + if (!arg) { + av_freep(&old_str); + return AVERROR(EINVAL); + } + + count_coefficients(arg, &iir->nb_ab[ab]); + + p = NULL; + iir->cache[ab] = av_calloc(iir->nb_ab[ab] + 1, sizeof(double)); + iir->ab[ab] = av_calloc(iir->nb_ab[ab] * (!!s->format + 1), sizeof(double)); + if (!iir->ab[ab] || !iir->cache[ab]) { + av_freep(&old_str); + return AVERROR(ENOMEM); + } + + if (s->format) { + ret = read_zp_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab], format[s->format]); + } else { + ret = read_tf_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab]); + } + if (ret < 0) { + av_freep(&old_str); + return ret; + } + prev_arg = arg; + } + + av_freep(&old_str); + + return 0; +} + +static void multiply(double wre, double wim, int npz, double *coeffs) +{ + double nwre = -wre, nwim = -wim; + double cre, cim; + int i; + + for (i = npz; i >= 1; i--) { + cre = coeffs[2 * i + 0]; + cim = coeffs[2 * i + 1]; + + coeffs[2 * i + 0] = (nwre * cre - nwim * cim) + coeffs[2 * (i - 1) + 0]; + coeffs[2 * i + 1] = (nwre * cim + nwim * cre) + coeffs[2 * (i - 1) + 1]; + } + + cre = coeffs[0]; + cim = coeffs[1]; + coeffs[0] = nwre * cre - nwim * cim; + coeffs[1] = nwre * cim + nwim * cre; +} + +static int expand(AVFilterContext *ctx, double *pz, int nb, double *coeffs) +{ + int i; + + coeffs[0] = 1.0; + coeffs[1] = 0.0; + + for (i = 0; i < nb; i++) { + coeffs[2 * (i + 1) ] = 0.0; + coeffs[2 * (i + 1) + 1] = 0.0; + } + + for (i = 0; i < nb; i++) + multiply(pz[2 * i], pz[2 * i + 1], nb, coeffs); + + for (i = 0; i < nb + 1; i++) { + if (fabs(coeffs[2 * i + 1]) > FLT_EPSILON) { + av_log(ctx, AV_LOG_ERROR, "coeff: %lf of z^%d is not real; poles/zeros are not complex conjugates.\n", + coeffs[2 * i + 1], i); + return AVERROR(EINVAL); + } + } + + return 0; +} + +static int convert_zp2tf(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch, i, j, ret = 0; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + double *topc, *botc; + + topc = av_calloc((iir->nb_ab[0] + 1) * 2, sizeof(*topc)); + botc = av_calloc((iir->nb_ab[1] + 1) * 2, sizeof(*botc)); + if (!topc || !botc) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = expand(ctx, iir->ab[0], iir->nb_ab[0], botc); + if (ret < 0) { + goto fail; + } + + ret = expand(ctx, iir->ab[1], iir->nb_ab[1], topc); + if (ret < 0) { + goto fail; + } + + for (j = 0, i = iir->nb_ab[1]; i >= 0; j++, i--) { + iir->ab[1][j] = topc[2 * i]; + } + iir->nb_ab[1]++; + + for (j = 0, i = iir->nb_ab[0]; i >= 0; j++, i--) { + iir->ab[0][j] = botc[2 * i]; + } + iir->nb_ab[0]++; + +fail: + av_free(topc); + av_free(botc); + if (ret < 0) + break; + } + + return ret; +} + +static int decompose_zp2biquads(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch, ret; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int nb_biquads = (FFMAX(iir->nb_ab[0], iir->nb_ab[1]) + 1) / 2; + int current_biquad = 0; + + iir->biquads = av_calloc(nb_biquads, sizeof(BiquadContext)); + if (!iir->biquads) + return AVERROR(ENOMEM); + + while (nb_biquads--) { + Pair outmost_pole = { -1, -1 }; + Pair nearest_zero = { -1, -1 }; + double zeros[4] = { 0 }; + double poles[4] = { 0 }; + double b[6] = { 0 }; + double a[6] = { 0 }; + double min_distance = DBL_MAX; + double max_mag = 0; + int i; + + for (i = 0; i < iir->nb_ab[0]; i++) { + double mag; + + if (isnan(iir->ab[0][2 * i]) || isnan(iir->ab[0][2 * i + 1])) + continue; + mag = hypot(iir->ab[0][2 * i], iir->ab[0][2 * i + 1]); + + if (mag > max_mag) { + max_mag = mag; + outmost_pole.a = i; + } + } + + for (i = 0; i < iir->nb_ab[1]; i++) { + if (isnan(iir->ab[0][2 * i]) || isnan(iir->ab[0][2 * i + 1])) + continue; + + if (iir->ab[0][2 * i ] == iir->ab[0][2 * outmost_pole.a ] && + iir->ab[0][2 * i + 1] == -iir->ab[0][2 * outmost_pole.a + 1]) { + outmost_pole.b = i; + break; + } + } + + av_log(ctx, AV_LOG_VERBOSE, "outmost_pole is %d.%d\n", outmost_pole.a, outmost_pole.b); + + if (outmost_pole.a < 0 || outmost_pole.b < 0) + return AVERROR(EINVAL); + + for (i = 0; i < iir->nb_ab[1]; i++) { + double distance; + + if (isnan(iir->ab[1][2 * i]) || isnan(iir->ab[1][2 * i + 1])) + continue; + distance = hypot(iir->ab[0][2 * outmost_pole.a ] - iir->ab[1][2 * i ], + iir->ab[0][2 * outmost_pole.a + 1] - iir->ab[1][2 * i + 1]); + + if (distance < min_distance) { + min_distance = distance; + nearest_zero.a = i; + } + } + + for (i = 0; i < iir->nb_ab[1]; i++) { + if (isnan(iir->ab[1][2 * i]) || isnan(iir->ab[1][2 * i + 1])) + continue; + + if (iir->ab[1][2 * i ] == iir->ab[1][2 * nearest_zero.a ] && + iir->ab[1][2 * i + 1] == -iir->ab[1][2 * nearest_zero.a + 1]) { + nearest_zero.b = i; + break; + } + } + + av_log(ctx, AV_LOG_VERBOSE, "nearest_zero is %d.%d\n", nearest_zero.a, nearest_zero.b); + + if (nearest_zero.a < 0 || nearest_zero.b < 0) + return AVERROR(EINVAL); + + poles[0] = iir->ab[0][2 * outmost_pole.a ]; + poles[1] = iir->ab[0][2 * outmost_pole.a + 1]; + + zeros[0] = iir->ab[1][2 * nearest_zero.a ]; + zeros[1] = iir->ab[1][2 * nearest_zero.a + 1]; + + if (nearest_zero.a == nearest_zero.b && outmost_pole.a == outmost_pole.b) { + zeros[2] = 0; + zeros[3] = 0; + + poles[2] = 0; + poles[3] = 0; + } else { + poles[2] = iir->ab[0][2 * outmost_pole.b ]; + poles[3] = iir->ab[0][2 * outmost_pole.b + 1]; + + zeros[2] = iir->ab[1][2 * nearest_zero.b ]; + zeros[3] = iir->ab[1][2 * nearest_zero.b + 1]; + } + + ret = expand(ctx, zeros, 2, b); + if (ret < 0) + return ret; + + ret = expand(ctx, poles, 2, a); + if (ret < 0) + return ret; + + iir->ab[0][2 * outmost_pole.a] = iir->ab[0][2 * outmost_pole.a + 1] = NAN; + iir->ab[0][2 * outmost_pole.b] = iir->ab[0][2 * outmost_pole.b + 1] = NAN; + iir->ab[1][2 * nearest_zero.a] = iir->ab[1][2 * nearest_zero.a + 1] = NAN; + iir->ab[1][2 * nearest_zero.b] = iir->ab[1][2 * nearest_zero.b + 1] = NAN; + + iir->biquads[current_biquad].a0 = 1.0; + iir->biquads[current_biquad].a1 = a[2] / a[4]; + iir->biquads[current_biquad].a2 = a[0] / a[4]; + iir->biquads[current_biquad].b0 = b[4] / a[4] * (current_biquad ? 1.0 : iir->g); + iir->biquads[current_biquad].b1 = b[2] / a[4] * (current_biquad ? 1.0 : iir->g); + iir->biquads[current_biquad].b2 = b[0] / a[4] * (current_biquad ? 1.0 : iir->g); + + av_log(ctx, AV_LOG_VERBOSE, "a=%lf %lf %lf:b=%lf %lf %lf\n", + iir->biquads[current_biquad].a0, + iir->biquads[current_biquad].a1, + iir->biquads[current_biquad].a2, + iir->biquads[current_biquad].b0, + iir->biquads[current_biquad].b1, + iir->biquads[current_biquad].b2); + + current_biquad++; + } + } + + return 0; +} + +static void convert_pr2zp(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int n; + + for (n = 0; n < iir->nb_ab[0]; n++) { + double r = iir->ab[0][2*n]; + double angle = iir->ab[0][2*n+1]; + + iir->ab[0][2*n] = r * cos(angle); + iir->ab[0][2*n+1] = r * sin(angle); + } + + for (n = 0; n < iir->nb_ab[1]; n++) { + double r = iir->ab[1][2*n]; + double angle = iir->ab[1][2*n+1]; + + iir->ab[1][2*n] = r * cos(angle); + iir->ab[1][2*n+1] = r * sin(angle); + } + } +} + +static void convert_pd2zp(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int n; + + for (n = 0; n < iir->nb_ab[0]; n++) { + double r = iir->ab[0][2*n]; + double angle = M_PI*iir->ab[0][2*n+1]/180.; + + iir->ab[0][2*n] = r * cos(angle); + iir->ab[0][2*n+1] = r * sin(angle); + } + + for (n = 0; n < iir->nb_ab[1]; n++) { + double r = iir->ab[1][2*n]; + double angle = M_PI*iir->ab[1][2*n+1]/180.; + + iir->ab[1][2*n] = r * cos(angle); + iir->ab[1][2*n+1] = r * sin(angle); + } + } +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioIIRContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + int ch, ret, i; + + s->channels = inlink->channels; + s->iir = av_calloc(s->channels, sizeof(*s->iir)); + if (!s->iir) + return AVERROR(ENOMEM); + + ret = read_gains(ctx, s->g_str, inlink->channels); + if (ret < 0) + return ret; + + ret = read_channels(ctx, inlink->channels, s->a_str, 0); + if (ret < 0) + return ret; + + ret = read_channels(ctx, inlink->channels, s->b_str, 1); + if (ret < 0) + return ret; + + if (s->format == 2) { + convert_pr2zp(ctx, inlink->channels); + } else if (s->format == 3) { + convert_pd2zp(ctx, inlink->channels); + } + + if (s->format == 0) + av_log(ctx, AV_LOG_WARNING, "tf coefficients format is not recommended for too high number of zeros/poles.\n"); + + if (s->format > 0 && s->process == 0) { + av_log(ctx, AV_LOG_WARNING, "Direct processsing is not recommended for zp coefficients format.\n"); + + ret = convert_zp2tf(ctx, inlink->channels); + if (ret < 0) + return ret; + } else if (s->format == 0 && s->process == 1) { + av_log(ctx, AV_LOG_ERROR, "Serial cascading is not implemented for transfer function.\n"); + return AVERROR_PATCHWELCOME; + } else if (s->format > 0 && s->process == 1) { + if (inlink->format == AV_SAMPLE_FMT_S16P) + av_log(ctx, AV_LOG_WARNING, "Serial cascading is not recommended for i16 precision.\n"); + + ret = decompose_zp2biquads(ctx, inlink->channels); + if (ret < 0) + return ret; + } + + for (ch = 0; ch < inlink->channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + + for (i = 1; i < iir->nb_ab[0]; i++) { + iir->ab[0][i] /= iir->ab[0][0]; + } + + for (i = 0; i < iir->nb_ab[1]; i++) { + iir->ab[1][i] *= iir->g / iir->ab[0][0]; + } + } + + switch (inlink->format) { + case AV_SAMPLE_FMT_DBLP: s->iir_channel = s->process == 1 ? iir_ch_serial_dblp : iir_ch_dblp; break; + case AV_SAMPLE_FMT_FLTP: s->iir_channel = s->process == 1 ? iir_ch_serial_fltp : iir_ch_fltp; break; + case AV_SAMPLE_FMT_S32P: s->iir_channel = s->process == 1 ? iir_ch_serial_s32p : iir_ch_s32p; break; + case AV_SAMPLE_FMT_S16P: s->iir_channel = s->process == 1 ? iir_ch_serial_s16p : iir_ch_s16p; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AudioIIRContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + ThreadData td; + AVFrame *out; + int ch; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + td.in = in; + td.out = out; + ctx->internal->execute(ctx, s->iir_channel, &td, NULL, outlink->channels); + + for (ch = 0; ch < outlink->channels; ch++) { + if (s->iir[ch].clippings > 0) + av_log(ctx, AV_LOG_WARNING, "Channel %d clipping %d times. Please reduce gain.\n", + ch, s->iir[ch].clippings); + s->iir[ch].clippings = 0; + } + + if (in != out) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static av_cold int init(AVFilterContext *ctx) +{ + AudioIIRContext *s = ctx->priv; + + if (!s->a_str || !s->b_str || !s->g_str) { + av_log(ctx, AV_LOG_ERROR, "Valid coefficients are mandatory.\n"); + return AVERROR(EINVAL); + } + + switch (s->precision) { + case 0: s->sample_format = AV_SAMPLE_FMT_DBLP; break; + case 1: s->sample_format = AV_SAMPLE_FMT_FLTP; break; + case 2: s->sample_format = AV_SAMPLE_FMT_S32P; break; + case 3: s->sample_format = AV_SAMPLE_FMT_S16P; break; + default: return AVERROR_BUG; + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + if (s->iir) { + for (ch = 0; ch < s->channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + av_freep(&iir->ab[0]); + av_freep(&iir->ab[1]); + av_freep(&iir->cache[0]); + av_freep(&iir->cache[1]); + av_freep(&iir->biquads); + } + } + av_freep(&s->iir); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(AudioIIRContext, x) +#define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption aiir_options[] = { + { "z", "set B/numerator/zeros coefficients", OFFSET(b_str), AV_OPT_TYPE_STRING, {.str="1+0i 1-0i"}, 0, 0, AF }, + { "p", "set A/denominator/poles coefficients", OFFSET(a_str), AV_OPT_TYPE_STRING, {.str="1+0i 1-0i"}, 0, 0, AF }, + { "k", "set channels gains", OFFSET(g_str), AV_OPT_TYPE_STRING, {.str="1|1"}, 0, 0, AF }, + { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, + { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, + { "f", "set coefficients format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=1}, 0, 3, AF, "format" }, + { "tf", "transfer function", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "format" }, + { "zp", "Z-plane zeros/poles", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "format" }, + { "pr", "Z-plane zeros/poles (polar radians)", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "format" }, + { "pd", "Z-plane zeros/poles (polar degrees)", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "format" }, + { "r", "set kind of processing", OFFSET(process), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "process" }, + { "d", "direct", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "process" }, + { "s", "serial cascading", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "process" }, + { "e", "set precision", OFFSET(precision),AV_OPT_TYPE_INT, {.i64=0}, 0, 3, AF, "precision" }, + { "dbl", "double-precision floating-point", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "precision" }, + { "flt", "single-precision floating-point", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision" }, + { "i32", "32-bit integers", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision" }, + { "i16", "16-bit integers", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision" }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(aiir); + +AVFilter ff_af_aiir = { + .name = "aiir", + .description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse Response filter with supplied coefficients."), + .priv_size = sizeof(AudioIIRContext), + .priv_class = &aiir_class, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c index 46211a710..0fc8e6baa 100644 --- a/libavfilter/af_alimiter.c +++ b/libavfilter/af_alimiter.c @@ -135,7 +135,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index 09848e5d9..ec764375c 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -490,12 +490,10 @@ static av_cold int init(AVFilterContext *ctx) int i, ret; for (i = 0; i < s->nb_inputs; i++) { - char name[32]; AVFilterPad pad = { 0 }; - snprintf(name, sizeof(name), "input%d", i); pad.type = AVMEDIA_TYPE_AUDIO; - pad.name = av_strdup(name); + pad.name = av_asprintf("input%d", i); if (!pad.name) return AVERROR(ENOMEM); diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c index dcffc216d..bf46cc8fa 100644 --- a/libavfilter/af_aphaser.c +++ b/libavfilter/af_aphaser.c @@ -247,7 +247,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inbuf) if (av_frame_is_writable(inbuf)) { outbuf = inbuf; } else { - outbuf = ff_get_audio_buffer(inlink, inbuf->nb_samples); + outbuf = ff_get_audio_buffer(outlink, inbuf->nb_samples); if (!outbuf) { av_frame_free(&inbuf); return AVERROR(ENOMEM); diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index 3c2f66b30..ecb76e64d 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -140,11 +140,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) return -1; } } - av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples); - if (asns->next_out_pts == AV_NOPTS_VALUE) + ret = av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples); + if (ret > 0 && asns->next_out_pts == AV_NOPTS_VALUE) asns->next_out_pts = insamples->pts; av_frame_free(&insamples); + if (ret < 0) + return ret; + while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples) push_samples(outlink); return 0; diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c index c4f619a42..d5c3823e6 100644 --- a/libavfilter/af_biquads.c +++ b/libavfilter/af_biquads.c @@ -73,7 +73,6 @@ enum FilterType { equalizer, bass, treble, - band, bandpass, bandreject, allpass, @@ -87,6 +86,8 @@ enum WidthType { OCTAVE, QFACTOR, SLOPE, + KHERTZ, + NB_WTYPE, }; typedef struct ChanCache { @@ -237,7 +238,7 @@ BIQUAD_FILTER(s32, int32_t, INT32_MIN, INT32_MAX, 1) BIQUAD_FILTER(flt, float, -1., 1., 0) BIQUAD_FILTER(dbl, double, -1., 1., 0) -static int config_output(AVFilterLink *outlink) +static int config_filter(AVFilterLink *outlink, int reset) { AVFilterContext *ctx = outlink->src; BiquadsContext *s = ctx->priv; @@ -260,6 +261,9 @@ static int config_output(AVFilterLink *outlink) case HERTZ: alpha = sin(w0) / (2 * s->frequency / s->width); break; + case KHERTZ: + alpha = sin(w0) / (2 * s->frequency / (s->width * 1000)); + break; case OCTAVE: alpha = sin(w0) * sinh(log(2.) / 2 * s->width * w0 / sin(w0)); break; @@ -371,16 +375,20 @@ static int config_output(AVFilterLink *outlink) av_assert0(0); } + av_log(ctx, AV_LOG_VERBOSE, "a=%lf %lf %lf:b=%lf %lf %lf\n", s->a0, s->a1, s->a2, s->b0, s->b1, s->b2); + s->a1 /= s->a0; s->a2 /= s->a0; s->b0 /= s->a0; s->b1 /= s->a0; s->b2 /= s->a0; + s->a0 /= s->a0; s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->channels); if (!s->cache) return AVERROR(ENOMEM); - memset(s->cache, 0, sizeof(ChanCache) * inlink->channels); + if (reset) + memset(s->cache, 0, sizeof(ChanCache) * inlink->channels); switch (inlink->format) { case AV_SAMPLE_FMT_S16P: s->filter = biquad_s16; break; @@ -395,6 +403,11 @@ static int config_output(AVFilterLink *outlink) return 0; } +static int config_output(AVFilterLink *outlink) +{ + return config_filter(outlink, 1); +} + static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; @@ -407,7 +420,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) if (av_frame_is_writable(buf)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(inlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) { av_frame_free(&buf); return AVERROR(ENOMEM); @@ -438,6 +451,117 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) return ff_filter_frame(outlink, out_buf); } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + BiquadsContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + if ((!strcmp(cmd, "frequency") || !strcmp(cmd, "f")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble || + s->filter_type == bandpass || + s->filter_type == bandreject|| + s->filter_type == lowpass || + s->filter_type == highpass || + s->filter_type == allpass)) { + double freq; + + if (sscanf(args, "%lf", &freq) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid frequency value.\n"); + return AVERROR(EINVAL); + } + + s->frequency = freq; + } else if ((!strcmp(cmd, "gain") || !strcmp(cmd, "g")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble)) { + double gain; + + if (sscanf(args, "%lf", &gain) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid gain value.\n"); + return AVERROR(EINVAL); + } + + s->gain = gain; + } else if ((!strcmp(cmd, "width") || !strcmp(cmd, "w")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble || + s->filter_type == bandpass || + s->filter_type == bandreject|| + s->filter_type == lowpass || + s->filter_type == highpass || + s->filter_type == allpass)) { + double width; + + if (sscanf(args, "%lf", &width) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid width value.\n"); + return AVERROR(EINVAL); + } + + s->width = width; + } else if ((!strcmp(cmd, "width_type") || !strcmp(cmd, "t")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble || + s->filter_type == bandpass || + s->filter_type == bandreject|| + s->filter_type == lowpass || + s->filter_type == highpass || + s->filter_type == allpass)) { + char width_type; + + if (sscanf(args, "%c", &width_type) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid width_type value.\n"); + return AVERROR(EINVAL); + } + + switch (width_type) { + case 'h': width_type = HERTZ; break; + case 'q': width_type = QFACTOR; break; + case 'o': width_type = OCTAVE; break; + case 's': width_type = SLOPE; break; + case 'k': width_type = KHERTZ; break; + default: + av_log(ctx, AV_LOG_ERROR, "Invalid width_type value: %c\n", width_type); + return AVERROR(EINVAL); + } + + s->width_type = width_type; + } else if ((!strcmp(cmd, "a0") || + !strcmp(cmd, "a1") || + !strcmp(cmd, "a2") || + !strcmp(cmd, "b0") || + !strcmp(cmd, "b1") || + !strcmp(cmd, "b2")) && + s->filter_type == biquad) { + double value; + + if (sscanf(args, "%lf", &value) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid biquad value.\n"); + return AVERROR(EINVAL); + } + + if (!strcmp(cmd, "a0")) + s->a0 = value; + else if (!strcmp(cmd, "a1")) + s->a1 = value; + else if (!strcmp(cmd, "a2")) + s->a2 = value; + else if (!strcmp(cmd, "b0")) + s->b0 = value; + else if (!strcmp(cmd, "b1")) + s->b1 = value; + else if (!strcmp(cmd, "b2")) + s->b2 = value; + } + + return config_filter(outlink, 0); +} + static av_cold void uninit(AVFilterContext *ctx) { BiquadsContext *s = ctx->priv; @@ -486,20 +610,22 @@ AVFilter ff_af_##name_ = { \ .inputs = inputs, \ .outputs = outputs, \ .priv_class = &name_##_class, \ + .process_command = process_command, \ } #if CONFIG_EQUALIZER_FILTER static const AVOption equalizer_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, - {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 999, FLAGS}, - {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 999, FLAGS}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 99999, FLAGS}, + {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, @@ -513,12 +639,13 @@ DEFINE_BIQUAD_FILTER(equalizer, "Apply two-pole peaking equalization (EQ) filter static const AVOption bass_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, @@ -534,12 +661,13 @@ DEFINE_BIQUAD_FILTER(bass, "Boost or cut lower frequencies."); static const AVOption treble_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, @@ -555,14 +683,15 @@ DEFINE_BIQUAD_FILTER(treble, "Boost or cut upper frequencies."); static const AVOption bandpass_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, - {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, - {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"csg", "use constant skirt gain", OFFSET(csg), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, @@ -575,14 +704,15 @@ DEFINE_BIQUAD_FILTER(bandpass, "Apply a two-pole Butterworth band-pass filter.") static const AVOption bandreject_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, - {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, - {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -594,12 +724,13 @@ DEFINE_BIQUAD_FILTER(bandreject, "Apply a two-pole Butterworth band-reject filte static const AVOption lowpass_options[] = { {"frequency", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=500}, 0, 999999, FLAGS}, {"f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=500}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, @@ -615,12 +746,13 @@ DEFINE_BIQUAD_FILTER(lowpass, "Apply a low-pass filter with 3dB point frequency. static const AVOption highpass_options[] = { {"frequency", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, @@ -636,12 +768,13 @@ DEFINE_BIQUAD_FILTER(highpass, "Apply a high-pass filter with 3dB point frequenc static const AVOption allpass_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS}, {"w", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, @@ -653,12 +786,12 @@ DEFINE_BIQUAD_FILTER(allpass, "Apply a two-pole all-pass filter."); #endif /* CONFIG_ALLPASS_FILTER */ #if CONFIG_BIQUAD_FILTER static const AVOption biquad_options[] = { - {"a0", NULL, OFFSET(a0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"a1", NULL, OFFSET(a1), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"a2", NULL, OFFSET(a2), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"b0", NULL, OFFSET(b0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"b1", NULL, OFFSET(b1), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"b2", NULL, OFFSET(b2), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, + {"a0", NULL, OFFSET(a0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT32_MIN, INT32_MAX, FLAGS}, + {"a1", NULL, OFFSET(a1), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"a2", NULL, OFFSET(a2), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"b0", NULL, OFFSET(b0), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"b1", NULL, OFFSET(b1), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"b2", NULL, OFFSET(b2), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c index b7cfd3815..c01b983cd 100644 --- a/libavfilter/af_bs2b.c +++ b/libavfilter/af_bs2b.c @@ -32,6 +32,8 @@ #include "formats.h" #include "internal.h" +typedef void (*filter_func)(t_bs2bdp bs2bdp, uint8_t *sample, int n); + typedef struct Bs2bContext { const AVClass *class; @@ -41,7 +43,7 @@ typedef struct Bs2bContext { t_bs2bdp bs2bp; - void (*filter)(t_bs2bdp bs2bdp, uint8_t *sample, int n); + filter_func filter; } Bs2bContext; #define OFFSET(x) offsetof(Bs2bContext, x) @@ -133,7 +135,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(outlink, frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); @@ -165,19 +167,19 @@ static int config_output(AVFilterLink *outlink) switch (inlink->format) { case AV_SAMPLE_FMT_U8: - bs2b->filter = bs2b_cross_feed_u8; + bs2b->filter = (filter_func) bs2b_cross_feed_u8; break; case AV_SAMPLE_FMT_S16: - bs2b->filter = (void*)bs2b_cross_feed_s16; + bs2b->filter = (filter_func) bs2b_cross_feed_s16; break; case AV_SAMPLE_FMT_S32: - bs2b->filter = (void*)bs2b_cross_feed_s32; + bs2b->filter = (filter_func) bs2b_cross_feed_s32; break; case AV_SAMPLE_FMT_FLT: - bs2b->filter = (void*)bs2b_cross_feed_f; + bs2b->filter = (filter_func) bs2b_cross_feed_f; break; case AV_SAMPLE_FMT_DBL: - bs2b->filter = (void*)bs2b_cross_feed_d; + bs2b->filter = (filter_func) bs2b_cross_feed_d; break; default: return AVERROR_BUG; diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 7c2be95bf..285d76a3e 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -149,13 +149,6 @@ static av_cold int channelmap_init(AVFilterContext *ctx) else mode = MAP_PAIR_STR_STR; } -#if FF_API_OLD_FILTER_OPTS - if (strchr(mapping, ',')) { - av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use " - "'|' to separate the mappings.\n"); - separator = ','; - } -#endif } if (mode != MAP_NONE) { diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c index 87c829009..29c47ab14 100644 --- a/libavfilter/af_chorus.c +++ b/libavfilter/af_chorus.c @@ -247,7 +247,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c index 8589b1ef0..c138f0b1d 100644 --- a/libavfilter/af_compand.c +++ b/libavfilter/af_compand.c @@ -185,7 +185,7 @@ static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); @@ -249,7 +249,7 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame) if (count >= s->delay_samples) { if (!out_frame) { - out_frame = ff_get_audio_buffer(inlink, nb_samples - i); + out_frame = ff_get_audio_buffer(ctx->outputs[0], nb_samples - i); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c index d5a348431..05285cd29 100644 --- a/libavfilter/af_compensationdelay.c +++ b/libavfilter/af_compensationdelay.c @@ -131,7 +131,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out; int n, ch; - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c index d3def92fb..a0af28043 100644 --- a/libavfilter/af_crossfeed.c +++ b/libavfilter/af_crossfeed.c @@ -99,7 +99,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_crystalizer.c b/libavfilter/af_crystalizer.c index dec30aa5f..5b27e1fb7 100644 --- a/libavfilter/af_crystalizer.c +++ b/libavfilter/af_crystalizer.c @@ -173,7 +173,7 @@ static void filter_dblp(void **d, void **p, const void **s, static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; - CrystalizerContext *s = ctx->priv; + CrystalizerContext *s = ctx->priv; switch (inlink->format) { case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; @@ -203,7 +203,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c index 6d33daee0..e007efe05 100644 --- a/libavfilter/af_dcshift.c +++ b/libavfilter/af_dcshift.c @@ -28,7 +28,7 @@ typedef struct DCShiftContext { const AVClass *class; double dcshift; - double limiterthreshhold; + double limiterthreshold; double limitergain; } DCShiftContext; @@ -47,7 +47,7 @@ static av_cold int init(AVFilterContext *ctx) { DCShiftContext *s = ctx->priv; - s->limiterthreshhold = INT32_MAX * (1.0 - (fabs(s->dcshift) - s->limitergain)); + s->limiterthreshold = INT32_MAX * (1.0 - (fabs(s->dcshift) - s->limitergain)); return 0; } @@ -111,14 +111,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) d = src[j]; - if (d > s->limiterthreshhold && dcshift > 0) { - d = (d - s->limiterthreshhold) * s->limitergain / - (INT32_MAX - s->limiterthreshhold) + - s->limiterthreshhold + dcshift; - } else if (d < -s->limiterthreshhold && dcshift < 0) { - d = (d + s->limiterthreshhold) * s->limitergain / - (INT32_MAX - s->limiterthreshhold) - - s->limiterthreshhold + dcshift; + if (d > s->limiterthreshold && dcshift > 0) { + d = (d - s->limiterthreshold) * s->limitergain / + (INT32_MAX - s->limiterthreshold) + + s->limiterthreshold + dcshift; + } else if (d < -s->limiterthreshold && dcshift < 0) { + d = (d + s->limiterthreshold) * s->limitergain / + (INT32_MAX - s->limiterthreshold) - + s->limiterthreshold + dcshift; } else { d = dcshift * INT32_MAX + d; } diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c index 7b880c86c..cdd2b4fc4 100644 --- a/libavfilter/af_earwax.c +++ b/libavfilter/af_earwax.c @@ -115,7 +115,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { AVFilterLink *outlink = inlink->dst->outputs[0]; int16_t *taps, *endin, *in, *out; - AVFrame *outsamples = ff_get_audio_buffer(inlink, insamples->nb_samples); + AVFrame *outsamples = ff_get_audio_buffer(outlink, insamples->nb_samples); int len; if (!outsamples) { diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c index a746006f7..13c6f4777 100644 --- a/libavfilter/af_extrastereo.c +++ b/libavfilter/af_extrastereo.c @@ -71,7 +71,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -90,9 +90,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) right = average + mult * (right - average); if (s->clip) { - dst[n * 2 ] = av_clipf(left, -1, 1); - dst[n * 2 + 1] = av_clipf(right, -1, 1); + left = av_clipf(left, -1, 1); + right = av_clipf(right, -1, 1); } + + dst[n * 2 ] = left; + dst[n * 2 + 1] = right; } if (out != in) diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c index a92367c97..b7497a12e 100644 --- a/libavfilter/af_flanger.c +++ b/libavfilter/af_flanger.c @@ -148,7 +148,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c index 691c251f5..0cfc93a7d 100644 --- a/libavfilter/af_haas.c +++ b/libavfilter/af_haas.c @@ -144,7 +144,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c index 3b76d1d73..2188f7ab2 100644 --- a/libavfilter/af_headphone.c +++ b/libavfilter/af_headphone.c @@ -324,16 +324,19 @@ static int read_ir(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; HeadphoneContext *s = ctx->priv; - int ir_len, max_ir_len, input_number; + int ir_len, max_ir_len, input_number, ret; for (input_number = 0; input_number < s->nb_inputs; input_number++) if (inlink == ctx->inputs[input_number]) break; - av_audio_fifo_write(s->in[input_number].fifo, (void **)frame->extended_data, - frame->nb_samples); + ret = av_audio_fifo_write(s->in[input_number].fifo, (void **)frame->extended_data, + frame->nb_samples); av_frame_free(&frame); + if (ret < 0) + return ret; + ir_len = av_audio_fifo_size(s->in[input_number].fifo); max_ir_len = 65536; if (ir_len > max_ir_len) { @@ -572,13 +575,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = ctx->outputs[0]; int ret = 0; - av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, - in->nb_samples); + ret = av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, + in->nb_samples); if (s->pts == AV_NOPTS_VALUE) s->pts = in->pts; av_frame_free(&in); + if (ret < 0) + return ret; + if (!s->have_hrirs && s->eof_hrirs) { ret = convert_coeffs(ctx, inlink); if (ret < 0) @@ -589,10 +595,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) while (av_audio_fifo_size(s->in[0].fifo) >= s->size) { ret = headphone_frame(s, outlink); if (ret < 0) - break; + return ret; } } - return ret; + + return 0; } static int query_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index f8af0a180..cf5131e8d 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -32,6 +32,7 @@ #include "audio.h" #include "avfilter.h" #include "formats.h" +#include "filters.h" #include "internal.h" typedef struct ChannelMap { @@ -78,48 +79,12 @@ static const AVOption join_options[] = { AVFILTER_DEFINE_CLASS(join); -static int try_push_frame(AVFilterContext *ctx); - -static int filter_frame(AVFilterLink *link, AVFrame *frame) -{ - AVFilterContext *ctx = link->dst; - JoinContext *s = ctx->priv; - int i, j; - - for (i = 0; i < ctx->nb_inputs; i++) - if (link == ctx->inputs[i]) - break; - av_assert0(i < ctx->nb_inputs); - av_assert0(!s->input_frames[i]); - s->input_frames[i] = frame; - - /* request the same number of samples on all inputs */ - /* FIXME that means a frame arriving asynchronously on a different input - will not have the requested number of samples */ - if (i == 0) { - int nb_samples = s->input_frames[0]->nb_samples; - - for (j = 1; !i && j < ctx->nb_inputs; j++) - ctx->inputs[j]->request_samples = nb_samples; - } - - return try_push_frame(ctx); -} - static int parse_maps(AVFilterContext *ctx) { JoinContext *s = ctx->priv; char separator = '|'; char *cur = s->map; -#if FF_API_OLD_FILTER_OPTS - if (cur && strchr(cur, ',')) { - av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use '|' to " - "separate the mappings.\n"); - separator = ','; - } -#endif - while (cur && *cur) { char *sep, *next, *p; uint64_t in_channel = 0, out_channel = 0; @@ -228,9 +193,6 @@ static av_cold int join_init(AVFilterContext *ctx) pad.name = av_strdup(name); if (!pad.name) return AVERROR(ENOMEM); - pad.filter_frame = filter_frame; - - pad.needs_fifo = 1; if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { av_freep(&pad.name); @@ -398,21 +360,6 @@ fail: return ret; } -static int join_request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - JoinContext *s = ctx->priv; - int i; - - /* get a frame on each input */ - for (i = 0; i < ctx->nb_inputs; i++) { - AVFilterLink *inlink = ctx->inputs[i]; - if (!s->input_frames[i]) - return ff_request_frame(inlink); - } - return 0; -} - static int try_push_frame(AVFilterContext *ctx) { AVFilterLink *outlink = ctx->outputs[0]; @@ -428,6 +375,8 @@ static int try_push_frame(AVFilterContext *ctx) return 0; nb_samples = FFMIN(nb_samples, s->input_frames[i]->nb_samples); } + if (!nb_samples) + return 0; /* setup the output frame */ frame = av_frame_alloc(); @@ -516,12 +465,58 @@ fail: return ret; } +static int activate(AVFilterContext *ctx) +{ + JoinContext *s = ctx->priv; + int i, ret, status; + int nb_samples = 0; + int64_t pts; + + if (!s->input_frames[0]) { + ret = ff_inlink_consume_frame(ctx->inputs[0], &s->input_frames[0]); + if (ret < 0) { + return ret; + } else if (ff_inlink_acknowledge_status(ctx->inputs[0], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0]) && !s->input_frames[0]) { + ff_inlink_request_frame(ctx->inputs[0]); + return 0; + } + } + } + + nb_samples = s->input_frames[0]->nb_samples; + + for (i = 1; i < ctx->nb_inputs && nb_samples > 0; i++) { + if (s->input_frames[i]) + continue; + + if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) { + ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->input_frames[i]); + if (ret < 0) { + return ret; + } else if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + ff_inlink_request_frame(ctx->inputs[i]); + return 0; + } + } + } + + return try_push_frame(ctx); +} + static const AVFilterPad avfilter_af_join_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = join_config_output, - .request_frame = join_request_frame, }, { NULL } }; @@ -534,6 +529,7 @@ AVFilter ff_af_join = { .priv_class = &join_class, .init = join_init, .uninit = join_uninit, + .activate = activate, .query_formats = join_query_formats, .inputs = NULL, .outputs = avfilter_af_join_outputs, diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c index 5532dacd7..3be26bc84 100644 --- a/libavfilter/af_ladspa.c +++ b/libavfilter/af_ladspa.c @@ -318,8 +318,6 @@ static int config_output(AVFilterLink *outlink) ret = 0; } else { - LADSPAContext *s = ctx->priv; - outlink->sample_rate = s->sample_rate; outlink->time_base = (AVRational){1, s->sample_rate}; diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c index e3e815e27..a7f11cbe6 100644 --- a/libavfilter/af_loudnorm.c +++ b/libavfilter/af_loudnorm.c @@ -423,7 +423,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c new file mode 100644 index 000000000..8a0a6fd88 --- /dev/null +++ b/libavfilter/af_lv2.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * Copyright (c) 2007-2016 David Robillard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * LV2 wrapper + */ + +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct URITable { + char **uris; + size_t n_uris; +} URITable; + +typedef struct LV2Context { + const AVClass *class; + char *plugin_uri; + char *options; + + unsigned nb_inputs; + unsigned nb_inputcontrols; + unsigned nb_outputs; + + int sample_rate; + int nb_samples; + int64_t pts; + int64_t duration; + + LilvWorld *world; + const LilvPlugin *plugin; + uint32_t nb_ports; + float *values; + URITable uri_table; + LV2_URID_Map map; + LV2_Feature map_feature; + LV2_URID_Unmap unmap; + LV2_Feature unmap_feature; + LV2_Atom_Sequence seq_in[2]; + LV2_Atom_Sequence *seq_out; + const LV2_Feature *features[5]; + + float *mins; + float *maxes; + float *controls; + + LilvInstance *instance; + + LilvNode *atom_AtomPort; + LilvNode *atom_Sequence; + LilvNode *lv2_AudioPort; + LilvNode *lv2_CVPort; + LilvNode *lv2_ControlPort; + LilvNode *lv2_Optional; + LilvNode *lv2_InputPort; + LilvNode *lv2_OutputPort; + LilvNode *urid_map; + LilvNode *powerOf2BlockLength; + LilvNode *fixedBlockLength; + LilvNode *boundedBlockLength; +} LV2Context; + +#define OFFSET(x) offsetof(LV2Context, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption lv2_options[] = { + { "plugin", "set plugin uri", OFFSET(plugin_uri), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "p", "set plugin uri", OFFSET(plugin_uri), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "controls", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "c", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS }, + { "s", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS }, + { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, + { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, + { "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, + { "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lv2); + +static void uri_table_init(URITable *table) +{ + table->uris = NULL; + table->n_uris = 0; +} + +static void uri_table_destroy(URITable *table) +{ + int i; + + for (i = 0; i < table->n_uris; i++) { + av_freep(&table->uris[i]); + } + + av_freep(&table->uris); +} + +static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri) +{ + URITable *table = (URITable*)handle; + const size_t len = strlen(uri); + size_t i; + char **tmp; + + for (i = 0; i < table->n_uris; i++) { + if (!strcmp(table->uris[i], uri)) { + return i + 1; + } + } + + tmp = av_calloc(table->n_uris + 1, sizeof(char*)); + if (!tmp) + return table->n_uris; + memcpy(tmp, table->uris, table->n_uris * sizeof(char**)); + + av_free(table->uris); + table->uris = tmp; + table->uris[table->n_uris] = av_malloc(len + 1); + if (!table->uris[table->n_uris]) + return table->n_uris; + + memcpy(table->uris[table->n_uris], uri, len + 1); + table->n_uris++; + + return table->n_uris; +} + +static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) +{ + URITable *table = (URITable*)handle; + + if (urid > 0 && urid <= table->n_uris) { + return table->uris[urid - 1]; + } + + return NULL; +} + +static void connect_ports(LV2Context *s, AVFrame *in, AVFrame *out) +{ + int ich = 0, och = 0, i; + + for (i = 0; i < s->nb_ports; i++) { + const LilvPort *port = lilv_plugin_get_port_by_index(s->plugin, i); + + if (lilv_port_is_a(s->plugin, port, s->lv2_AudioPort) || + lilv_port_is_a(s->plugin, port, s->lv2_CVPort)) { + if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort)) { + lilv_instance_connect_port(s->instance, i, in->extended_data[ich++]); + } else if (lilv_port_is_a(s->plugin, port, s->lv2_OutputPort)) { + lilv_instance_connect_port(s->instance, i, out->extended_data[och++]); + } else { + av_log(s, AV_LOG_WARNING, "port %d neither input nor output, skipping\n", i); + } + } else if (lilv_port_is_a(s->plugin, port, s->atom_AtomPort)) { + if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort)) { + lilv_instance_connect_port(s->instance, i, &s->seq_in); + } else { + lilv_instance_connect_port(s->instance, i, s->seq_out); + } + } else if (lilv_port_is_a(s->plugin, port, s->lv2_ControlPort)) { + lilv_instance_connect_port(s->instance, i, &s->controls[i]); + } + } + + s->seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body); + s->seq_in[0].atom.type = uri_table_map(&s->uri_table, LV2_ATOM__Sequence); + s->seq_out->atom.size = 9624; + s->seq_out->atom.type = uri_table_map(&s->uri_table, LV2_ATOM__Chunk); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + LV2Context *s = ctx->priv; + AVFrame *out; + + if (!s->nb_outputs || + (av_frame_is_writable(in) && s->nb_inputs == s->nb_outputs)) { + out = in; + } else { + out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + connect_ports(s, in, out); + + lilv_instance_run(s->instance, in->nb_samples); + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(ctx->outputs[0], out); +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + LV2Context *s = ctx->priv; + AVFrame *out; + int64_t t; + + if (ctx->nb_inputs) + return ff_request_frame(ctx->inputs[0]); + + t = av_rescale(s->pts, AV_TIME_BASE, s->sample_rate); + if (s->duration >= 0 && t >= s->duration) + return AVERROR_EOF; + + out = ff_get_audio_buffer(outlink, s->nb_samples); + if (!out) + return AVERROR(ENOMEM); + + connect_ports(s, out, out); + + lilv_instance_run(s->instance, out->nb_samples); + + out->sample_rate = s->sample_rate; + out->pts = s->pts; + s->pts += s->nb_samples; + + return ff_filter_frame(outlink, out); +} + +static const LV2_Feature buf_size_features[3] = { + { LV2_BUF_SIZE__powerOf2BlockLength, NULL }, + { LV2_BUF_SIZE__fixedBlockLength, NULL }, + { LV2_BUF_SIZE__boundedBlockLength, NULL }, +}; + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + LV2Context *s = ctx->priv; + char *p, *arg, *saveptr = NULL; + int i, sample_rate; + + uri_table_init(&s->uri_table); + s->map.handle = &s->uri_table; + s->map.map = uri_table_map; + s->map_feature.URI = LV2_URID_MAP_URI; + s->map_feature.data = &s->map; + s->unmap.handle = &s->uri_table; + s->unmap.unmap = uri_table_unmap; + s->unmap_feature.URI = LV2_URID_UNMAP_URI; + s->unmap_feature.data = &s->unmap; + s->features[0] = &s->map_feature; + s->features[1] = &s->unmap_feature; + s->features[2] = &buf_size_features[0]; + s->features[3] = &buf_size_features[1]; + s->features[4] = &buf_size_features[2]; + + if (ctx->nb_inputs) { + AVFilterLink *inlink = ctx->inputs[0]; + + outlink->format = inlink->format; + outlink->sample_rate = sample_rate = inlink->sample_rate; + if (s->nb_inputs == s->nb_outputs) { + outlink->channel_layout = inlink->channel_layout; + outlink->channels = inlink->channels; + } + + } else { + outlink->sample_rate = sample_rate = s->sample_rate; + outlink->time_base = (AVRational){1, s->sample_rate}; + } + + s->instance = lilv_plugin_instantiate(s->plugin, sample_rate, s->features); + if (!s->instance) { + av_log(s, AV_LOG_ERROR, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(s->plugin))); + return AVERROR(EINVAL); + } + + s->mins = av_calloc(s->nb_ports, sizeof(float)); + s->maxes = av_calloc(s->nb_ports, sizeof(float)); + s->controls = av_calloc(s->nb_ports, sizeof(float)); + + if (!s->mins || !s->maxes || !s->controls) + return AVERROR(ENOMEM); + + lilv_plugin_get_port_ranges_float(s->plugin, s->mins, s->maxes, s->controls); + s->seq_out = av_malloc(sizeof(LV2_Atom_Sequence) + 9624); + if (!s->seq_out) + return AVERROR(ENOMEM); + + if (s->options && !strcmp(s->options, "help")) { + if (!s->nb_inputcontrols) { + av_log(ctx, AV_LOG_INFO, + "The '%s' plugin does not have any input controls.\n", + s->plugin_uri); + } else { + av_log(ctx, AV_LOG_INFO, + "The '%s' plugin has the following input controls:\n", + s->plugin_uri); + for (i = 0; i < s->nb_ports; i++) { + const LilvPort *port = lilv_plugin_get_port_by_index(s->plugin, i); + const LilvNode *symbol = lilv_port_get_symbol(s->plugin, port); + LilvNode *name = lilv_port_get_name(s->plugin, port); + + if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort) && + lilv_port_is_a(s->plugin, port, s->lv2_ControlPort)) { + av_log(ctx, AV_LOG_INFO, "%s\t\t (from %f to %f) (default %f)\t\t%s\n", + lilv_node_as_string(symbol), s->mins[i], s->maxes[i], s->controls[i], + lilv_node_as_string(name)); + } + + lilv_node_free(name); + } + } + return AVERROR_EXIT; + } + + p = s->options; + while (s->options) { + const LilvPort *port; + LilvNode *sym; + float val; + char *str, *vstr; + int index; + + if (!(arg = av_strtok(p, " |", &saveptr))) + break; + p = NULL; + + vstr = strstr(arg, "="); + if (vstr == NULL) { + av_log(ctx, AV_LOG_ERROR, "Invalid syntax.\n"); + return AVERROR(EINVAL); + } + + vstr[0] = 0; + str = arg; + val = atof(vstr+1); + sym = lilv_new_string(s->world, str); + port = lilv_plugin_get_port_by_symbol(s->plugin, sym); + lilv_node_free(sym); + if (!port) { + av_log(s, AV_LOG_WARNING, "Unknown option: <%s>\n", str); + } else { + index = lilv_port_get_index(s->plugin, port); + s->controls[index] = val; + } + } + + if (s->nb_inputs && + (lilv_plugin_has_feature(s->plugin, s->powerOf2BlockLength) || + lilv_plugin_has_feature(s->plugin, s->fixedBlockLength) || + lilv_plugin_has_feature(s->plugin, s->boundedBlockLength))) { + AVFilterLink *inlink = ctx->inputs[0]; + + inlink->partial_buf_size = inlink->min_samples = inlink->max_samples = 4096; + } + + return 0; +} + +static av_cold int init(AVFilterContext *ctx) +{ + LV2Context *s = ctx->priv; + const LilvPlugins *plugins; + const LilvPlugin *plugin; + AVFilterPad pad = { NULL }; + LilvNode *uri; + int i; + + s->world = lilv_world_new(); + if (!s->world) + return AVERROR(ENOMEM); + + uri = lilv_new_uri(s->world, s->plugin_uri); + if (!uri) { + av_log(s, AV_LOG_ERROR, "Invalid plugin URI <%s>\n", s->plugin_uri); + return AVERROR(EINVAL); + } + + lilv_world_load_all(s->world); + plugins = lilv_world_get_all_plugins(s->world); + plugin = lilv_plugins_get_by_uri(plugins, uri); + lilv_node_free(uri); + + if (!plugin) { + av_log(s, AV_LOG_ERROR, "Plugin <%s> not found\n", s->plugin_uri); + return AVERROR(EINVAL); + } + + s->plugin = plugin; + s->nb_ports = lilv_plugin_get_num_ports(s->plugin); + + s->lv2_InputPort = lilv_new_uri(s->world, LV2_CORE__InputPort); + s->lv2_OutputPort = lilv_new_uri(s->world, LV2_CORE__OutputPort); + s->lv2_AudioPort = lilv_new_uri(s->world, LV2_CORE__AudioPort); + s->lv2_ControlPort = lilv_new_uri(s->world, LV2_CORE__ControlPort); + s->lv2_Optional = lilv_new_uri(s->world, LV2_CORE__connectionOptional); + s->atom_AtomPort = lilv_new_uri(s->world, LV2_ATOM__AtomPort); + s->atom_Sequence = lilv_new_uri(s->world, LV2_ATOM__Sequence); + s->urid_map = lilv_new_uri(s->world, LV2_URID__map); + s->powerOf2BlockLength = lilv_new_uri(s->world, LV2_BUF_SIZE__powerOf2BlockLength); + s->fixedBlockLength = lilv_new_uri(s->world, LV2_BUF_SIZE__fixedBlockLength); + s->boundedBlockLength = lilv_new_uri(s->world, LV2_BUF_SIZE__boundedBlockLength); + + for (i = 0; i < s->nb_ports; i++) { + const LilvPort *lport = lilv_plugin_get_port_by_index(s->plugin, i); + int is_input = 0; + int is_optional = 0; + + is_optional = lilv_port_has_property(s->plugin, lport, s->lv2_Optional); + + if (lilv_port_is_a(s->plugin, lport, s->lv2_InputPort)) { + is_input = 1; + } else if (!lilv_port_is_a(s->plugin, lport, s->lv2_OutputPort) && !is_optional) { + return AVERROR(EINVAL); + } + + if (lilv_port_is_a(s->plugin, lport, s->lv2_ControlPort)) { + if (is_input) { + s->nb_inputcontrols++; + } + } else if (lilv_port_is_a(s->plugin, lport, s->lv2_AudioPort)) { + if (is_input) { + s->nb_inputs++; + } else { + s->nb_outputs++; + } + } + } + + pad.type = AVMEDIA_TYPE_AUDIO; + + if (s->nb_inputs) { + pad.name = av_asprintf("in0:%s:%u", s->plugin_uri, s->nb_inputs); + if (!pad.name) + return AVERROR(ENOMEM); + + pad.filter_frame = filter_frame; + if (ff_insert_inpad(ctx, ctx->nb_inputs, &pad) < 0) { + av_freep(&pad.name); + return AVERROR(ENOMEM); + } + } + + return 0; +} + +static int query_formats(AVFilterContext *ctx) +{ + LV2Context *s = ctx->priv; + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + AVFilterLink *outlink = ctx->outputs[0]; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + if (s->nb_inputs) { + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + + ret = ff_set_common_samplerates(ctx, formats); + if (ret < 0) + return ret; + } else { + int sample_rates[] = { s->sample_rate, -1 }; + + ret = ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates)); + if (ret < 0) + return ret; + } + + if (s->nb_inputs == 2 && s->nb_outputs == 2) { + layouts = NULL; + ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO); + if (ret < 0) + return ret; + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + } else { + if (s->nb_inputs >= 1) { + AVFilterLink *inlink = ctx->inputs[0]; + uint64_t inlayout = FF_COUNT2LAYOUT(s->nb_inputs); + + layouts = NULL; + ret = ff_add_channel_layout(&layouts, inlayout); + if (ret < 0) + return ret; + ret = ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts); + if (ret < 0) + return ret; + + if (!s->nb_outputs) { + ret = ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); + if (ret < 0) + return ret; + } + } + + if (s->nb_outputs >= 1) { + uint64_t outlayout = FF_COUNT2LAYOUT(s->nb_outputs); + + layouts = NULL; + ret = ff_add_channel_layout(&layouts, outlayout); + if (ret < 0) + return ret; + ret = ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + LV2Context *s = ctx->priv; + + lilv_node_free(s->powerOf2BlockLength); + lilv_node_free(s->fixedBlockLength); + lilv_node_free(s->boundedBlockLength); + lilv_node_free(s->urid_map); + lilv_node_free(s->atom_Sequence); + lilv_node_free(s->atom_AtomPort); + lilv_node_free(s->lv2_Optional); + lilv_node_free(s->lv2_ControlPort); + lilv_node_free(s->lv2_AudioPort); + lilv_node_free(s->lv2_OutputPort); + lilv_node_free(s->lv2_InputPort); + uri_table_destroy(&s->uri_table); + lilv_instance_free(s->instance); + lilv_world_free(s->world); + av_freep(&s->mins); + av_freep(&s->maxes); + av_freep(&s->controls); + av_freep(&s->seq_out); + + if (ctx->nb_inputs) + av_freep(&ctx->input_pads[0].name); +} + +static const AVFilterPad lv2_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + .request_frame = request_frame, + }, + { NULL } +}; + +AVFilter ff_af_lv2 = { + .name = "lv2", + .description = NULL_IF_CONFIG_SMALL("Apply LV2 effect."), + .priv_size = sizeof(LV2Context), + .priv_class = &lv2_class, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = 0, + .outputs = lv2_outputs, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, +}; diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c new file mode 100644 index 000000000..02f987a6a --- /dev/null +++ b/libavfilter/af_mcompand.c @@ -0,0 +1,689 @@ +/* + * COpyright (c) 2002 Daniel Pouzzner + * Copyright (c) 1999 Chris Bagwell + * Copyright (c) 1999 Nick Bailey + * Copyright (c) 2007 Rob Sykes + * Copyright (c) 2013 Paul B Mahol + * Copyright (c) 2014 Andrew Kelley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 multiband compand filter + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/ffmath.h" +#include "libavutil/opt.h" +#include "libavutil/samplefmt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct CompandSegment { + double x, y; + double a, b; +} CompandSegment; + +typedef struct CompandT { + CompandSegment *segments; + int nb_segments; + double in_min_lin; + double out_min_lin; + double curve_dB; + double gain_dB; +} CompandT; + +#define N 4 + +typedef struct PrevCrossover { + double in; + double out_low; + double out_high; +} PrevCrossover[N * 2]; + +typedef struct Crossover { + PrevCrossover *previous; + size_t pos; + double coefs[3 *(N+1)]; +} Crossover; + +typedef struct CompBand { + CompandT transfer_fn; + double *attack_rate; + double *decay_rate; + double *volume; + double delay; + double topfreq; + Crossover filter; + AVFrame *delay_buf; + size_t delay_size; + ptrdiff_t delay_buf_ptr; + size_t delay_buf_cnt; +} CompBand; + +typedef struct MCompandContext { + const AVClass *class; + + char *args; + + int nb_bands; + CompBand *bands; + AVFrame *band_buf1, *band_buf2, *band_buf3; + int band_samples; + size_t delay_buf_size; +} MCompandContext; + +#define OFFSET(x) offsetof(MCompandContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption mcompand_options[] = { + { "args", "set parameters for each band", OFFSET(args), AV_OPT_TYPE_STRING, { .str = "0.005,0.1 6 -47/-40,-34/-34,-17/-33 100 | 0.003,0.05 6 -47/-40,-34/-34,-17/-33 400 | 0.000625,0.0125 6 -47/-40,-34/-34,-15/-33 1600 | 0.0001,0.025 6 -47/-40,-34/-34,-31/-31,-0/-30 6400 | 0,0.025 6 -38/-31,-28/-28,-0/-25 22000" }, 0, 0, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(mcompand); + +static av_cold void uninit(AVFilterContext *ctx) +{ + MCompandContext *s = ctx->priv; + int i; + + av_frame_free(&s->band_buf1); + av_frame_free(&s->band_buf2); + av_frame_free(&s->band_buf3); + + if (s->bands) { + for (i = 0; i < s->nb_bands; i++) { + av_freep(&s->bands[i].attack_rate); + av_freep(&s->bands[i].decay_rate); + av_freep(&s->bands[i].volume); + av_freep(&s->bands[i].transfer_fn.segments); + av_freep(&s->bands[i].filter.previous); + av_frame_free(&s->bands[i].delay_buf); + } + } + av_freep(&s->bands); +} + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterChannelLayouts *layouts; + AVFilterFormats *formats; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static void count_items(char *item_str, int *nb_items, char delimiter) +{ + char *p; + + *nb_items = 1; + for (p = item_str; *p; p++) { + if (*p == delimiter) + (*nb_items)++; + } +} + +static void update_volume(CompBand *cb, double in, int ch) +{ + double delta = in - cb->volume[ch]; + + if (delta > 0.0) + cb->volume[ch] += delta * cb->attack_rate[ch]; + else + cb->volume[ch] += delta * cb->decay_rate[ch]; +} + +static double get_volume(CompandT *s, double in_lin) +{ + CompandSegment *cs; + double in_log, out_log; + int i; + + if (in_lin <= s->in_min_lin) + return s->out_min_lin; + + in_log = log(in_lin); + + for (i = 1; i < s->nb_segments; i++) + if (in_log <= s->segments[i].x) + break; + cs = &s->segments[i - 1]; + in_log -= cs->x; + out_log = cs->y + in_log * (cs->a * in_log + cs->b); + + return exp(out_log); +} + +static int parse_points(char *points, int nb_points, double radius, + CompandT *s, AVFilterContext *ctx) +{ + int new_nb_items, num; + char *saveptr = NULL; + char *p = points; + int i; + +#define S(x) s->segments[2 * ((x) + 1)] + for (i = 0, new_nb_items = 0; i < nb_points; i++) { + char *tstr = av_strtok(p, ",", &saveptr); + p = NULL; + if (!tstr || sscanf(tstr, "%lf/%lf", &S(i).x, &S(i).y) != 2) { + av_log(ctx, AV_LOG_ERROR, + "Invalid and/or missing input/output value.\n"); + return AVERROR(EINVAL); + } + if (i && S(i - 1).x > S(i).x) { + av_log(ctx, AV_LOG_ERROR, + "Transfer function input values must be increasing.\n"); + return AVERROR(EINVAL); + } + S(i).y -= S(i).x; + av_log(ctx, AV_LOG_DEBUG, "%d: x=%f y=%f\n", i, S(i).x, S(i).y); + new_nb_items++; + } + num = new_nb_items; + + /* Add 0,0 if necessary */ + if (num == 0 || S(num - 1).x) + num++; + +#undef S +#define S(x) s->segments[2 * (x)] + /* Add a tail off segment at the start */ + S(0).x = S(1).x - 2 * s->curve_dB; + S(0).y = S(1).y; + num++; + + /* Join adjacent colinear segments */ + for (i = 2; i < num; i++) { + double g1 = (S(i - 1).y - S(i - 2).y) * (S(i - 0).x - S(i - 1).x); + double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x); + int j; + + if (fabs(g1 - g2)) + continue; + num--; + for (j = --i; j < num; j++) + S(j) = S(j + 1); + } + + for (i = 0; i < s->nb_segments; i += 2) { + s->segments[i].y += s->gain_dB; + s->segments[i].x *= M_LN10 / 20; + s->segments[i].y *= M_LN10 / 20; + } + +#define L(x) s->segments[i - (x)] + for (i = 4; i < s->nb_segments; i += 2) { + double x, y, cx, cy, in1, in2, out1, out2, theta, len, r; + + L(4).a = 0; + L(4).b = (L(2).y - L(4).y) / (L(2).x - L(4).x); + + L(2).a = 0; + L(2).b = (L(0).y - L(2).y) / (L(0).x - L(2).x); + + theta = atan2(L(2).y - L(4).y, L(2).x - L(4).x); + len = hypot(L(2).x - L(4).x, L(2).y - L(4).y); + r = FFMIN(radius, len); + L(3).x = L(2).x - r * cos(theta); + L(3).y = L(2).y - r * sin(theta); + + theta = atan2(L(0).y - L(2).y, L(0).x - L(2).x); + len = hypot(L(0).x - L(2).x, L(0).y - L(2).y); + r = FFMIN(radius, len / 2); + x = L(2).x + r * cos(theta); + y = L(2).y + r * sin(theta); + + cx = (L(3).x + L(2).x + x) / 3; + cy = (L(3).y + L(2).y + y) / 3; + + L(2).x = x; + L(2).y = y; + + in1 = cx - L(3).x; + out1 = cy - L(3).y; + in2 = L(2).x - L(3).x; + out2 = L(2).y - L(3).y; + L(3).a = (out2 / in2 - out1 / in1) / (in2 - in1); + L(3).b = out1 / in1 - L(3).a * in1; + } + L(3).x = 0; + L(3).y = L(2).y; + + s->in_min_lin = exp(s->segments[1].x); + s->out_min_lin = exp(s->segments[1].y); + + return 0; +} + +static void square_quadratic(double const *x, double *y) +{ + y[0] = x[0] * x[0]; + y[1] = 2 * x[0] * x[1]; + y[2] = 2 * x[0] * x[2] + x[1] * x[1]; + y[3] = 2 * x[1] * x[2]; + y[4] = x[2] * x[2]; +} + +static int crossover_setup(AVFilterLink *outlink, Crossover *p, double frequency) +{ + double w0 = 2 * M_PI * frequency / outlink->sample_rate; + double Q = sqrt(.5), alpha = sin(w0) / (2*Q); + double x[9], norm; + int i; + + if (w0 > M_PI) + return AVERROR(EINVAL); + + x[0] = (1 - cos(w0))/2; /* Cf. filter_LPF in biquads.c */ + x[1] = 1 - cos(w0); + x[2] = (1 - cos(w0))/2; + x[3] = (1 + cos(w0))/2; /* Cf. filter_HPF in biquads.c */ + x[4] = -(1 + cos(w0)); + x[5] = (1 + cos(w0))/2; + x[6] = 1 + alpha; + x[7] = -2*cos(w0); + x[8] = 1 - alpha; + + for (norm = x[6], i = 0; i < 9; ++i) + x[i] /= norm; + + square_quadratic(x , p->coefs); + square_quadratic(x + 3, p->coefs + 5); + square_quadratic(x + 6, p->coefs + 10); + + p->previous = av_calloc(outlink->channels, sizeof(*p->previous)); + if (!p->previous) + return AVERROR(ENOMEM); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + MCompandContext *s = ctx->priv; + int ret, ch, i, k, new_nb_items, nb_bands; + char *p = s->args, *saveptr = NULL; + int max_delay_size = 0; + + count_items(s->args, &nb_bands, '|'); + s->nb_bands = FFMAX(1, nb_bands); + + s->bands = av_calloc(nb_bands, sizeof(*s->bands)); + if (!s->bands) + return AVERROR(ENOMEM); + + for (i = 0, new_nb_items = 0; i < nb_bands; i++) { + int nb_points, nb_attacks, nb_items = 0; + char *tstr2, *tstr = av_strtok(p, "|", &saveptr); + char *p2, *p3, *saveptr2 = NULL, *saveptr3 = NULL; + double radius; + + if (!tstr) { + uninit(ctx); + return AVERROR(EINVAL); + } + p = NULL; + + p2 = tstr; + count_items(tstr, &nb_items, ' '); + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "at least one attacks/decays rate is mandatory\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + p2 = NULL; + p3 = tstr2; + + count_items(tstr2, &nb_attacks, ','); + if (!nb_attacks || nb_attacks & 1) { + av_log(ctx, AV_LOG_ERROR, "number of attacks rate plus decays rate must be even\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + s->bands[i].attack_rate = av_calloc(outlink->channels, sizeof(double)); + s->bands[i].decay_rate = av_calloc(outlink->channels, sizeof(double)); + s->bands[i].volume = av_calloc(outlink->channels, sizeof(double)); + for (k = 0; k < FFMIN(nb_attacks / 2, outlink->channels); k++) { + char *tstr3 = av_strtok(p3, ",", &saveptr3); + + p3 = NULL; + sscanf(tstr3, "%lf", &s->bands[i].attack_rate[k]); + tstr3 = av_strtok(p3, ",", &saveptr3); + sscanf(tstr3, "%lf", &s->bands[i].decay_rate[k]); + + if (s->bands[i].attack_rate[k] > 1.0 / outlink->sample_rate) { + s->bands[i].attack_rate[k] = 1.0 - exp(-1.0 / (outlink->sample_rate * s->bands[i].attack_rate[k])); + } else { + s->bands[i].attack_rate[k] = 1.0; + } + + if (s->bands[i].decay_rate[k] > 1.0 / outlink->sample_rate) { + s->bands[i].decay_rate[k] = 1.0 - exp(-1.0 / (outlink->sample_rate * s->bands[i].decay_rate[k])); + } else { + s->bands[i].decay_rate[k] = 1.0; + } + } + + for (ch = k; ch < outlink->channels; ch++) { + s->bands[i].attack_rate[ch] = s->bands[i].attack_rate[k - 1]; + s->bands[i].decay_rate[ch] = s->bands[i].decay_rate[k - 1]; + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "transfer function curve in dB must be set\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + sscanf(tstr2, "%lf", &s->bands[i].transfer_fn.curve_dB); + + radius = s->bands[i].transfer_fn.curve_dB * M_LN10 / 20.0; + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "transfer points missing\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + count_items(tstr2, &nb_points, ','); + s->bands[i].transfer_fn.nb_segments = (nb_points + 4) * 2; + s->bands[i].transfer_fn.segments = av_calloc(s->bands[i].transfer_fn.nb_segments, + sizeof(CompandSegment)); + if (!s->bands[i].transfer_fn.segments) { + uninit(ctx); + return AVERROR(ENOMEM); + } + + ret = parse_points(tstr2, nb_points, radius, &s->bands[i].transfer_fn, ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "transfer points parsing failed\n"); + uninit(ctx); + return ret; + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "crossover_frequency is missing\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + new_nb_items += sscanf(tstr2, "%lf", &s->bands[i].topfreq) == 1; + if (s->bands[i].topfreq < 0 || s->bands[i].topfreq >= outlink->sample_rate / 2) { + av_log(ctx, AV_LOG_ERROR, "crossover_frequency should be >=0 and lower than half of sample rate\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + if (s->bands[i].topfreq != 0) { + ret = crossover_setup(outlink, &s->bands[i].filter, s->bands[i].topfreq); + if (ret < 0) { + uninit(ctx); + return ret; + } + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (tstr2) { + sscanf(tstr2, "%lf", &s->bands[i].delay); + max_delay_size = FFMAX(max_delay_size, s->bands[i].delay * outlink->sample_rate); + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (tstr2) { + double initial_volume; + + sscanf(tstr2, "%lf", &initial_volume); + initial_volume = pow(10.0, initial_volume / 20); + + for (k = 0; k < outlink->channels; k++) { + s->bands[i].volume[k] = initial_volume; + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (tstr2) { + sscanf(tstr2, "%lf", &s->bands[i].transfer_fn.gain_dB); + } + } + } + } + s->nb_bands = new_nb_items; + + for (i = 0; max_delay_size > 0 && i < s->nb_bands; i++) { + s->bands[i].delay_buf = ff_get_audio_buffer(outlink, max_delay_size); + if (!s->bands[i].delay_buf) + return AVERROR(ENOMEM); + } + s->delay_buf_size = max_delay_size; + + return 0; +} + +#define CONVOLVE _ _ _ _ + +static void crossover(int ch, Crossover *p, + double *ibuf, double *obuf_low, + double *obuf_high, size_t len) +{ + double out_low, out_high; + + while (len--) { + p->pos = p->pos ? p->pos - 1 : N - 1; +#define _ out_low += p->coefs[j] * p->previous[ch][p->pos + j].in \ + - p->coefs[2*N+2 + j] * p->previous[ch][p->pos + j].out_low, j++; + { + int j = 1; + out_low = p->coefs[0] * *ibuf; + CONVOLVE + *obuf_low++ = out_low; + } +#undef _ +#define _ out_high += p->coefs[j+N+1] * p->previous[ch][p->pos + j].in \ + - p->coefs[2*N+2 + j] * p->previous[ch][p->pos + j].out_high, j++; + { + int j = 1; + out_high = p->coefs[N+1] * *ibuf; + CONVOLVE + *obuf_high++ = out_high; + } + p->previous[ch][p->pos + N].in = p->previous[ch][p->pos].in = *ibuf++; + p->previous[ch][p->pos + N].out_low = p->previous[ch][p->pos].out_low = out_low; + p->previous[ch][p->pos + N].out_high = p->previous[ch][p->pos].out_high = out_high; + } +} + +static int mcompand_channel(MCompandContext *c, CompBand *l, double *ibuf, double *obuf, int len, int ch) +{ + int i; + + for (i = 0; i < len; i++) { + double level_in_lin, level_out_lin, checkbuf; + /* Maintain the volume fields by simulating a leaky pump circuit */ + update_volume(l, fabs(ibuf[i]), ch); + + /* Volume memory is updated: perform compand */ + level_in_lin = l->volume[ch]; + level_out_lin = get_volume(&l->transfer_fn, level_in_lin); + + if (c->delay_buf_size <= 0) { + checkbuf = ibuf[i] * level_out_lin; + obuf[i] = checkbuf; + } else { + double *delay_buf = (double *)l->delay_buf->extended_data[ch]; + + /* FIXME: note that this lookahead algorithm is really lame: + the response to a peak is released before the peak + arrives. */ + + /* because volume application delays differ band to band, but + total delay doesn't, the volume is applied in an iteration + preceding that in which the sample goes to obuf, except in + the band(s) with the longest vol app delay. + + the offset between delay_buf_ptr and the sample to apply + vol to, is a constant equal to the difference between this + band's delay and the longest delay of all the bands. */ + + if (l->delay_buf_cnt >= l->delay_size) { + checkbuf = + delay_buf[(l->delay_buf_ptr + + c->delay_buf_size - + l->delay_size) % c->delay_buf_size] * level_out_lin; + delay_buf[(l->delay_buf_ptr + c->delay_buf_size - + l->delay_size) % c->delay_buf_size] = checkbuf; + } + if (l->delay_buf_cnt >= c->delay_buf_size) { + obuf[i] = delay_buf[l->delay_buf_ptr]; + } else { + l->delay_buf_cnt++; + } + delay_buf[l->delay_buf_ptr++] = ibuf[i]; + l->delay_buf_ptr %= c->delay_buf_size; + } + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + MCompandContext *s = ctx->priv; + AVFrame *out, *abuf, *bbuf, *cbuf; + int ch, band, i; + + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + if (s->band_samples < in->nb_samples) { + av_frame_free(&s->band_buf1); + av_frame_free(&s->band_buf2); + av_frame_free(&s->band_buf3); + + s->band_buf1 = ff_get_audio_buffer(outlink, in->nb_samples); + s->band_buf2 = ff_get_audio_buffer(outlink, in->nb_samples); + s->band_buf3 = ff_get_audio_buffer(outlink, in->nb_samples); + s->band_samples = in->nb_samples; + } + + for (ch = 0; ch < outlink->channels; ch++) { + double *a, *dst = (double *)out->extended_data[ch]; + + for (band = 0, abuf = in, bbuf = s->band_buf2, cbuf = s->band_buf1; band < s->nb_bands; band++) { + CompBand *b = &s->bands[band]; + + if (b->topfreq) { + crossover(ch, &b->filter, (double *)abuf->extended_data[ch], + (double *)bbuf->extended_data[ch], (double *)cbuf->extended_data[ch], in->nb_samples); + } else { + bbuf = abuf; + abuf = cbuf; + } + + if (abuf == in) + abuf = s->band_buf3; + mcompand_channel(s, b, (double *)bbuf->extended_data[ch], (double *)abuf->extended_data[ch], out->nb_samples, ch); + a = (double *)abuf->extended_data[ch]; + for (i = 0; i < out->nb_samples; i++) { + dst[i] += a[i]; + } + + FFSWAP(AVFrame *, abuf, cbuf); + } + } + + out->pts = in->pts; + av_frame_free(&in); + return ff_filter_frame(outlink, out); +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + int ret; + + ret = ff_request_frame(ctx->inputs[0]); + + return ret; +} + +static const AVFilterPad mcompand_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad mcompand_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .request_frame = request_frame, + .config_props = config_output, + }, + { NULL } +}; + + +AVFilter ff_af_mcompand = { + .name = "mcompand", + .description = NULL_IF_CONFIG_SMALL( + "Multiband Compress or expand audio dynamic range."), + .query_formats = query_formats, + .priv_size = sizeof(MCompandContext), + .priv_class = &mcompand_class, + .uninit = uninit, + .inputs = mcompand_inputs, + .outputs = mcompand_outputs, +}; diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 23b29419b..d8a63a795 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -166,6 +166,7 @@ static av_cold int init(AVFilterContext *ctx) goto fail; } /* gains */ + sign = 1; while (1) { gain = 1; if (sscanf(arg, "%lf%n *%n", &gain, &len, &len)) diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c index c8f6f9666..97617346e 100644 --- a/libavfilter/af_replaygain.c +++ b/libavfilter/af_replaygain.c @@ -554,7 +554,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) uint32_t level; AVFrame *out; - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index ded25449d..ea6f4ff2c 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -128,7 +128,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) nb_samples = rubberband_available(s->rbs); if (nb_samples > 0) { - out = ff_get_audio_buffer(inlink, nb_samples); + out = ff_get_audio_buffer(outlink, nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -187,7 +187,7 @@ static int request_frame(AVFilterLink *outlink) nb_samples = rubberband_available(s->rbs); if (nb_samples > 0) { - out = ff_get_audio_buffer(inlink, nb_samples); + out = ff_get_audio_buffer(outlink, nb_samples); if (!out) return AVERROR(ENOMEM); out->pts = av_rescale_q(s->nb_samples_out, diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index 55bed4384..888049eaf 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -241,14 +241,13 @@ static int activate(AVFilterContext *ctx) } FF_FILTER_FORWARD_STATUS(ctx->inputs[0], ctx->outputs[0]); FF_FILTER_FORWARD_STATUS(ctx->inputs[1], ctx->outputs[0]); - /* TODO reindent */ - if (ff_outlink_frame_wanted(ctx->outputs[0])) { - if (!av_audio_fifo_size(s->fifo[0])) - ff_inlink_request_frame(ctx->inputs[0]); - if (!av_audio_fifo_size(s->fifo[1])) - ff_inlink_request_frame(ctx->inputs[1]); - } - return 0; + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + if (!av_audio_fifo_size(s->fifo[0])) + ff_inlink_request_frame(ctx->inputs[0]); + if (!av_audio_fifo_size(s->fifo[1])) + ff_inlink_request_frame(ctx->inputs[1]); + } + return 0; } static int query_formats(AVFilterContext *ctx) @@ -368,7 +367,7 @@ static int acompressor_filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index af5046305..d826a22e9 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -186,8 +186,17 @@ static int config_input(AVFilterLink *inlink) s->start_duration = av_rescale(s->start_duration, inlink->sample_rate, AV_TIME_BASE); + if (s->start_duration < 0) { + av_log(ctx, AV_LOG_WARNING, "start duration must be non-negative\n"); + s->start_duration = -s->start_duration; + } + s->stop_duration = av_rescale(s->stop_duration, inlink->sample_rate, AV_TIME_BASE); + if (s->stop_duration < 0) { + av_log(ctx, AV_LOG_WARNING, "stop duration must be non-negative\n"); + s->stop_duration = -s->stop_duration; + } s->start_holdoff = av_malloc_array(FFMAX(s->start_duration, 1), sizeof(*s->start_holdoff) * @@ -469,7 +478,7 @@ static int request_frame(AVFilterLink *outlink) (AVRational){1, outlink->sample_rate}, outlink->time_base); - ret = ff_filter_frame(ctx->inputs[0], frame); + ret = ff_filter_frame(outlink, frame); } s->mode = SILENCE_STOP; } diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c index a5e0b427f..7e529783d 100644 --- a/libavfilter/af_stereotools.c +++ b/libavfilter/af_stereotools.c @@ -166,7 +166,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c index 24146ff1d..ef16fcec7 100644 --- a/libavfilter/af_stereowiden.c +++ b/libavfilter/af_stereowiden.c @@ -98,7 +98,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c index c7122379d..460e18cd5 100644 --- a/libavfilter/af_surround.c +++ b/libavfilter/af_surround.c @@ -90,6 +90,15 @@ typedef struct AudioSurroundContext { float mag_total, float x, float y, int n); + void (*upmix_5_0)(AVFilterContext *ctx, + float c_re, float c_im, + float mag_totall, float mag_totalr, + float fl_phase, float fr_phase, + float bl_phase, float br_phase, + float sl_phase, float sr_phase, + float xl, float yl, + float xr, float yr, + int n); void (*upmix_5_1)(AVFilterContext *ctx, float c_re, float c_im, float lfe_re, float lfe_im, @@ -764,6 +773,66 @@ static void upmix_7_1(AVFilterContext *ctx, dstrs[2 * n + 1] = rs_mag * sinf(r_phase); } +static void upmix_7_1_5_0_side(AVFilterContext *ctx, + float c_re, float c_im, + float mag_totall, float mag_totalr, + float fl_phase, float fr_phase, + float bl_phase, float br_phase, + float sl_phase, float sr_phase, + float xl, float yl, + float xr, float yr, + int n) +{ + float fl_mag, fr_mag, ls_mag, rs_mag, lb_mag, rb_mag; + float *dstc, *dstl, *dstr, *dstls, *dstrs, *dstlb, *dstrb, *dstlfe; + float lfe_mag, c_phase, mag_total = (mag_totall + mag_totalr) * 0.5; + AudioSurroundContext *s = ctx->priv; + + dstl = (float *)s->output->extended_data[0]; + dstr = (float *)s->output->extended_data[1]; + dstc = (float *)s->output->extended_data[2]; + dstlfe = (float *)s->output->extended_data[3]; + dstlb = (float *)s->output->extended_data[4]; + dstrb = (float *)s->output->extended_data[5]; + dstls = (float *)s->output->extended_data[6]; + dstrs = (float *)s->output->extended_data[7]; + + c_phase = atan2f(c_im, c_re); + + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + + fl_mag = sqrtf(.5f * (xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; + fr_mag = sqrtf(.5f * (xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; + lb_mag = sqrtf(.5f * (-xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; + rb_mag = sqrtf(.5f * (-xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; + ls_mag = sqrtf(1.f - fabsf(xl)) * ((yl + 1.f) * .5f) * mag_totall; + rs_mag = sqrtf(1.f - fabsf(xr)) * ((yr + 1.f) * .5f) * mag_totalr; + + dstl[2 * n ] = fl_mag * cosf(fl_phase); + dstl[2 * n + 1] = fl_mag * sinf(fl_phase); + + dstr[2 * n ] = fr_mag * cosf(fr_phase); + dstr[2 * n + 1] = fr_mag * sinf(fr_phase); + + dstc[2 * n ] = c_re; + dstc[2 * n + 1] = c_im; + + dstlfe[2 * n ] = lfe_mag * cosf(c_phase); + dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase); + + dstlb[2 * n ] = lb_mag * cosf(bl_phase); + dstlb[2 * n + 1] = lb_mag * sinf(bl_phase); + + dstrb[2 * n ] = rb_mag * cosf(br_phase); + dstrb[2 * n + 1] = rb_mag * sinf(br_phase); + + dstls[2 * n ] = ls_mag * cosf(sl_phase); + dstls[2 * n + 1] = ls_mag * sinf(sl_phase); + + dstrs[2 * n ] = rs_mag * cosf(sr_phase); + dstrs[2 * n + 1] = rs_mag * sinf(sr_phase); +} + static void upmix_7_1_5_1(AVFilterContext *ctx, float c_re, float c_im, float lfe_re, float lfe_im, @@ -918,6 +987,118 @@ static void filter_2_1(AVFilterContext *ctx) } } +static void filter_5_0_side(AVFilterContext *ctx) +{ + AudioSurroundContext *s = ctx->priv; + float *srcl, *srcr, *srcc, *srcsl, *srcsr; + int n; + + srcl = (float *)s->input->extended_data[0]; + srcr = (float *)s->input->extended_data[1]; + srcc = (float *)s->input->extended_data[2]; + srcsl = (float *)s->input->extended_data[3]; + srcsr = (float *)s->input->extended_data[4]; + + for (n = 0; n < s->buf_size; n++) { + float fl_re = srcl[2 * n], fr_re = srcr[2 * n]; + float fl_im = srcl[2 * n + 1], fr_im = srcr[2 * n + 1]; + float c_re = srcc[2 * n], c_im = srcc[2 * n + 1]; + float sl_re = srcsl[2 * n], sl_im = srcsl[2 * n + 1]; + float sr_re = srcsr[2 * n], sr_im = srcsr[2 * n + 1]; + float fl_mag = hypotf(fl_re, fl_im); + float fr_mag = hypotf(fr_re, fr_im); + float fl_phase = atan2f(fl_im, fl_re); + float fr_phase = atan2f(fr_im, fr_re); + float sl_mag = hypotf(sl_re, sl_im); + float sr_mag = hypotf(sr_re, sr_im); + float sl_phase = atan2f(sl_im, sl_re); + float sr_phase = atan2f(sr_im, sr_re); + float phase_difl = fabsf(fl_phase - sl_phase); + float phase_difr = fabsf(fr_phase - sr_phase); + float mag_difl = (fl_mag - sl_mag) / (fl_mag + sl_mag); + float mag_difr = (fr_mag - sr_mag) / (fr_mag + sr_mag); + float mag_totall = hypotf(fl_mag, sl_mag); + float mag_totalr = hypotf(fr_mag, sr_mag); + float bl_phase = atan2f(fl_im + sl_im, fl_re + sl_re); + float br_phase = atan2f(fr_im + sr_im, fr_re + sr_re); + float xl, yl; + float xr, yr; + + if (phase_difl > M_PI) + phase_difl = 2 * M_PI - phase_difl; + + if (phase_difr > M_PI) + phase_difr = 2 * M_PI - phase_difr; + + stereo_position(mag_difl, phase_difl, &xl, &yl); + stereo_position(mag_difr, phase_difr, &xr, &yr); + + s->upmix_5_0(ctx, c_re, c_im, + mag_totall, mag_totalr, + fl_phase, fr_phase, + bl_phase, br_phase, + sl_phase, sr_phase, + xl, yl, xr, yr, n); + } +} + +static void filter_5_1_side(AVFilterContext *ctx) +{ + AudioSurroundContext *s = ctx->priv; + float *srcl, *srcr, *srcc, *srclfe, *srcsl, *srcsr; + int n; + + srcl = (float *)s->input->extended_data[0]; + srcr = (float *)s->input->extended_data[1]; + srcc = (float *)s->input->extended_data[2]; + srclfe = (float *)s->input->extended_data[3]; + srcsl = (float *)s->input->extended_data[4]; + srcsr = (float *)s->input->extended_data[5]; + + for (n = 0; n < s->buf_size; n++) { + float fl_re = srcl[2 * n], fr_re = srcr[2 * n]; + float fl_im = srcl[2 * n + 1], fr_im = srcr[2 * n + 1]; + float c_re = srcc[2 * n], c_im = srcc[2 * n + 1]; + float lfe_re = srclfe[2 * n], lfe_im = srclfe[2 * n + 1]; + float sl_re = srcsl[2 * n], sl_im = srcsl[2 * n + 1]; + float sr_re = srcsr[2 * n], sr_im = srcsr[2 * n + 1]; + float fl_mag = hypotf(fl_re, fl_im); + float fr_mag = hypotf(fr_re, fr_im); + float fl_phase = atan2f(fl_im, fl_re); + float fr_phase = atan2f(fr_im, fr_re); + float sl_mag = hypotf(sl_re, sl_im); + float sr_mag = hypotf(sr_re, sr_im); + float sl_phase = atan2f(sl_im, sl_re); + float sr_phase = atan2f(sr_im, sr_re); + float phase_difl = fabsf(fl_phase - sl_phase); + float phase_difr = fabsf(fr_phase - sr_phase); + float mag_difl = (fl_mag - sl_mag) / (fl_mag + sl_mag); + float mag_difr = (fr_mag - sr_mag) / (fr_mag + sr_mag); + float mag_totall = hypotf(fl_mag, sl_mag); + float mag_totalr = hypotf(fr_mag, sr_mag); + float bl_phase = atan2f(fl_im + sl_im, fl_re + sl_re); + float br_phase = atan2f(fr_im + sr_im, fr_re + sr_re); + float xl, yl; + float xr, yr; + + if (phase_difl > M_PI) + phase_difl = 2 * M_PI - phase_difl; + + if (phase_difr > M_PI) + phase_difr = 2 * M_PI - phase_difr; + + stereo_position(mag_difl, phase_difl, &xl, &yl); + stereo_position(mag_difr, phase_difr, &xr, &yr); + + s->upmix_5_1(ctx, c_re, c_im, lfe_re, lfe_im, + mag_totall, mag_totalr, + fl_phase, fr_phase, + bl_phase, br_phase, + sl_phase, sr_phase, + xl, yl, xr, yr, n); + } +} + static void filter_5_1_back(AVFilterContext *ctx) { AudioSurroundContext *s = ctx->priv; @@ -1063,6 +1244,26 @@ static int init(AVFilterContext *ctx) goto fail; } break; + case AV_CH_LAYOUT_5POINT0: + s->filter = filter_5_0_side; + switch (s->out_channel_layout) { + case AV_CH_LAYOUT_7POINT1: + s->upmix_5_0 = upmix_7_1_5_0_side; + break; + default: + goto fail; + } + break; + case AV_CH_LAYOUT_5POINT1: + s->filter = filter_5_1_side; + switch (s->out_channel_layout) { + case AV_CH_LAYOUT_7POINT1: + s->upmix_5_1 = upmix_7_1_5_1; + break; + default: + goto fail; + } + break; case AV_CH_LAYOUT_5POINT1_BACK: s->filter = filter_5_1_back; switch (s->out_channel_layout) { @@ -1149,18 +1350,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; AudioSurroundContext *s = ctx->priv; + int ret; - av_audio_fifo_write(s->fifo, (void **)in->extended_data, - in->nb_samples); - - if (s->pts == AV_NOPTS_VALUE) + ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, + in->nb_samples); + if (ret >= 0 && s->pts == AV_NOPTS_VALUE) s->pts = in->pts; av_frame_free(&in); + if (ret < 0) + return ret; while (av_audio_fifo_size(s->fifo) >= s->buf_size) { AVFrame *out; - int ret; ret = av_audio_fifo_peek(s->fifo, (void **)s->input->extended_data, s->buf_size); if (ret < 0) diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c index 572e9e3b5..8cbc79892 100644 --- a/libavfilter/af_tremolo.c +++ b/libavfilter/af_tremolo.c @@ -57,7 +57,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c index c7691f2f2..22bbab623 100644 --- a/libavfilter/af_vibrato.c +++ b/libavfilter/af_vibrato.c @@ -63,7 +63,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c index 3d76f12f2..b106ed8cf 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -410,7 +410,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) && (vol->precision != PRECISION_FIXED || vol->volume_i > 0)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(inlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) { av_frame_free(&buf); return AVERROR(ENOMEM); diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9b672a7a7..42516bbdf 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -22,7 +22,6 @@ #include "libavutil/thread.h" #include "avfilter.h" #include "config.h" -#include "opencl_allkernels.h" #define REGISTER_FILTER(X, x, y) \ @@ -42,6 +41,7 @@ static void register_all(void) { REGISTER_FILTER(ABENCH, abench, af); REGISTER_FILTER(ACOMPRESSOR, acompressor, af); + REGISTER_FILTER(ACONTRAST, acontrast, af); REGISTER_FILTER(ACOPY, acopy, af); REGISTER_FILTER(ACROSSFADE, acrossfade, af); REGISTER_FILTER(ACRUSHER, acrusher, af); @@ -54,6 +54,7 @@ static void register_all(void) REGISTER_FILTER(AFIR, afir, af); REGISTER_FILTER(AFORMAT, aformat, af); REGISTER_FILTER(AGATE, agate, af); + REGISTER_FILTER(AIIR, aiir, af); REGISTER_FILTER(AINTERLEAVE, ainterleave, af); REGISTER_FILTER(ALIMITER, alimiter, af); REGISTER_FILTER(ALLPASS, allpass, af); @@ -112,6 +113,8 @@ static void register_all(void) REGISTER_FILTER(LADSPA, ladspa, af); REGISTER_FILTER(LOUDNORM, loudnorm, af); REGISTER_FILTER(LOWPASS, lowpass, af); + REGISTER_FILTER(LV2, lv2, af); + REGISTER_FILTER(MCOMPAND, mcompand, af); REGISTER_FILTER(PAN, pan, af); REGISTER_FILTER(REPLAYGAIN, replaygain, af); REGISTER_FILTER(RESAMPLE, resample, af); @@ -135,6 +138,7 @@ static void register_all(void) REGISTER_FILTER(ANOISESRC, anoisesrc, asrc); REGISTER_FILTER(ANULLSRC, anullsrc, asrc); REGISTER_FILTER(FLITE, flite, asrc); + REGISTER_FILTER(HILBERT, hilbert, asrc); REGISTER_FILTER(SINE, sine, asrc); REGISTER_FILTER(ANULLSINK, anullsink, asink); @@ -173,6 +177,7 @@ static void register_all(void) REGISTER_FILTER(DCTDNOIZ, dctdnoiz, vf); REGISTER_FILTER(DEBAND, deband, vf); REGISTER_FILTER(DECIMATE, decimate, vf); + REGISTER_FILTER(DECONVOLVE, deconvolve, vf); REGISTER_FILTER(DEFLATE, deflate, vf); REGISTER_FILTER(DEFLICKER, deflicker, vf); REGISTER_FILTER(DEINTERLACE_QSV,deinterlace_qsv,vf); @@ -191,6 +196,7 @@ static void register_all(void) REGISTER_FILTER(DRAWTEXT, drawtext, vf); REGISTER_FILTER(EDGEDETECT, edgedetect, vf); REGISTER_FILTER(ELBG, elbg, vf); + REGISTER_FILTER(ENTROPY, entropy, vf); REGISTER_FILTER(EQ, eq, vf); REGISTER_FILTER(EROSION, erosion, vf); REGISTER_FILTER(EXTRACTPLANES, extractplanes, vf); @@ -200,6 +206,7 @@ static void register_all(void) REGISTER_FILTER(FIELDHINT, fieldhint, vf); REGISTER_FILTER(FIELDMATCH, fieldmatch, vf); REGISTER_FILTER(FIELDORDER, fieldorder, vf); + REGISTER_FILTER(FILLBORDERS, fillborders, vf); REGISTER_FILTER(FIND_RECT, find_rect, vf); REGISTER_FILTER(FLOODFILL, floodfill, vf); REGISTER_FILTER(FORMAT, format, vf); @@ -249,17 +256,21 @@ static void register_all(void) REGISTER_FILTER(METADATA, metadata, vf); REGISTER_FILTER(MIDEQUALIZER, midequalizer, vf); REGISTER_FILTER(MINTERPOLATE, minterpolate, vf); + REGISTER_FILTER(MIX, mix, vf); REGISTER_FILTER(MPDECIMATE, mpdecimate, vf); REGISTER_FILTER(NEGATE, negate, vf); REGISTER_FILTER(NLMEANS, nlmeans, vf); REGISTER_FILTER(NNEDI, nnedi, vf); REGISTER_FILTER(NOFORMAT, noformat, vf); REGISTER_FILTER(NOISE, noise, vf); + REGISTER_FILTER(NORMALIZE, normalize, vf); REGISTER_FILTER(NULL, null, vf); REGISTER_FILTER(OCR, ocr, vf); REGISTER_FILTER(OCV, ocv, vf); REGISTER_FILTER(OSCILLOSCOPE, oscilloscope, vf); REGISTER_FILTER(OVERLAY, overlay, vf); + REGISTER_FILTER(OVERLAY_OPENCL, overlay_opencl, vf); + REGISTER_FILTER(OVERLAY_QSV, overlay_qsv, vf); REGISTER_FILTER(OWDENOISE, owdenoise, vf); REGISTER_FILTER(PAD, pad, vf); REGISTER_FILTER(PALETTEGEN, palettegen, vf); @@ -273,6 +284,7 @@ static void register_all(void) REGISTER_FILTER(PP7, pp7, vf); REGISTER_FILTER(PREMULTIPLY, premultiply, vf); REGISTER_FILTER(PREWITT, prewitt, vf); + REGISTER_FILTER(PROGRAM_OPENCL, program_opencl, vf); REGISTER_FILTER(PSEUDOCOLOR, pseudocolor, vf); REGISTER_FILTER(PSNR, psnr, vf); REGISTER_FILTER(PULLUP, pullup, vf); @@ -302,6 +314,7 @@ static void register_all(void) REGISTER_FILTER(SETDAR, setdar, vf); REGISTER_FILTER(SETFIELD, setfield, vf); REGISTER_FILTER(SETPTS, setpts, vf); + REGISTER_FILTER(SETRANGE, setrange, vf); REGISTER_FILTER(SETSAR, setsar, vf); REGISTER_FILTER(SETTB, settb, vf); REGISTER_FILTER(SHOWINFO, showinfo, vf); @@ -335,6 +348,7 @@ static void register_all(void) REGISTER_FILTER(TRIM, trim, vf); REGISTER_FILTER(UNPREMULTIPLY, unpremultiply, vf); REGISTER_FILTER(UNSHARP, unsharp, vf); + REGISTER_FILTER(UNSHARP_OPENCL, unsharp_opencl, vf); REGISTER_FILTER(USPP, uspp, vf); REGISTER_FILTER(VAGUEDENOISER, vaguedenoiser, vf); REGISTER_FILTER(VECTORSCOPE, vectorscope, vf); @@ -343,6 +357,7 @@ static void register_all(void) REGISTER_FILTER(VIDSTABTRANSFORM, vidstabtransform, vf); REGISTER_FILTER(VIGNETTE, vignette, vf); REGISTER_FILTER(VMAFMOTION, vmafmotion, vf); + REGISTER_FILTER(VPP_QSV, vpp_qsv, vf); REGISTER_FILTER(VSTACK, vstack, vf); REGISTER_FILTER(W3FDIF, w3fdif, vf); REGISTER_FILTER(WAVEFORM, waveform, vf); @@ -364,6 +379,7 @@ static void register_all(void) REGISTER_FILTER(MANDELBROT, mandelbrot, vsrc); REGISTER_FILTER(MPTESTSRC, mptestsrc, vsrc); REGISTER_FILTER(NULLSRC, nullsrc, vsrc); + REGISTER_FILTER(OPENCLSRC, openclsrc, vsrc); REGISTER_FILTER(RGBTESTSRC, rgbtestsrc, vsrc); REGISTER_FILTER(SMPTEBARS, smptebars, vsrc); REGISTER_FILTER(SMPTEHDBARS, smptehdbars, vsrc); @@ -401,7 +417,6 @@ static void register_all(void) REGISTER_FILTER_UNCONDITIONAL(vsink_buffer); REGISTER_FILTER_UNCONDITIONAL(af_afifo); REGISTER_FILTER_UNCONDITIONAL(vf_fifo); - ff_opencl_register_filter_kernel_code_all(); } void avfilter_register_all(void) diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c new file mode 100644 index 000000000..a3a395254 --- /dev/null +++ b/libavfilter/asrc_hilbert.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2018 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 "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" +#include "window_func.h" + +typedef struct HilbertContext { + const AVClass *class; + + int sample_rate; + int nb_taps; + int nb_samples; + int win_func; + + float *taps; + int64_t pts; +} HilbertContext; + +#define OFFSET(x) offsetof(HilbertContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption hilbert_options[] = { + { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, FLAGS }, + { "r", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, FLAGS }, + { "taps", "set number of taps", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=22051}, 11, UINT16_MAX, FLAGS }, + { "t", "set number of taps", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=22051}, 11, UINT16_MAX, FLAGS }, + { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, FLAGS }, + { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, FLAGS }, + { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64=WFUNC_BLACKMAN}, 0, NB_WFUNC-1, FLAGS, "win_func" }, + { "w", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64=WFUNC_BLACKMAN}, 0, NB_WFUNC-1, FLAGS, "win_func" }, + { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" }, + { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, FLAGS, "win_func" }, + { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" }, + { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, FLAGS, "win_func" }, + { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, FLAGS, "win_func" }, + { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, FLAGS, "win_func" }, + { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, FLAGS, "win_func" }, + { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, FLAGS, "win_func" }, + { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, FLAGS, "win_func" }, + { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, FLAGS, "win_func" }, + { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, FLAGS, "win_func" }, + { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, FLAGS, "win_func" }, + { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" }, + { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" }, + { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" }, + { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" }, + { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" }, + { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" }, + { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" }, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(hilbert); + +static av_cold int init(AVFilterContext *ctx) +{ + HilbertContext *s = ctx->priv; + + if (!(s->nb_taps & 1)) { + av_log(s, AV_LOG_ERROR, "Number of taps %d must be odd length.\n", s->nb_taps); + return AVERROR(EINVAL); + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + HilbertContext *s = ctx->priv; + + av_freep(&s->taps); +} + +static av_cold int query_formats(AVFilterContext *ctx) +{ + HilbertContext *s = ctx->priv; + static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 }; + int sample_rates[] = { s->sample_rate, -1 }; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE + }; + + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats (ctx, formats); + if (ret < 0) + return ret; + + layouts = avfilter_make_format64_list(chlayouts); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_rates); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static av_cold int config_props(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + HilbertContext *s = ctx->priv; + float overlap; + int i; + + s->taps = av_malloc_array(s->nb_taps, sizeof(*s->taps)); + if (!s->taps) + return AVERROR(ENOMEM); + + generate_window_func(s->taps, s->nb_taps, s->win_func, &overlap); + + for (i = 0; i < s->nb_taps; i++) { + int k = -(s->nb_taps / 2) + i; + + if (k & 1) { + float pk = M_PI * k; + + s->taps[i] *= (1.f - cosf(pk)) / pk; + } else { + s->taps[i] = 0.f; + } + } + + s->pts = 0; + + return 0; +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + HilbertContext *s = ctx->priv; + AVFrame *frame; + int nb_samples; + + nb_samples = FFMIN(s->nb_samples, s->nb_taps - s->pts); + if (!nb_samples) + return AVERROR_EOF; + + if (!(frame = ff_get_audio_buffer(outlink, nb_samples))) + return AVERROR(ENOMEM); + + memcpy(frame->data[0], s->taps + s->pts, nb_samples * sizeof(float)); + + frame->pts = s->pts; + s->pts += nb_samples; + return ff_filter_frame(outlink, frame); +} + +static const AVFilterPad hilbert_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .request_frame = request_frame, + .config_props = config_props, + }, + { NULL } +}; + +AVFilter ff_asrc_hilbert = { + .name = "hilbert", + .description = NULL_IF_CONFIG_SMALL("Generate a Hilbert transform FIR coefficients."), + .query_formats = query_formats, + .init = init, + .uninit = uninit, + .priv_size = sizeof(HilbertContext), + .inputs = NULL, + .outputs = hilbert_outputs, + .priv_class = &hilbert_class, +}; diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c index c8ff0698e..725ac8bbd 100644 --- a/libavfilter/avf_avectorscope.c +++ b/libavfilter/avf_avectorscope.c @@ -65,6 +65,8 @@ typedef struct AudioVectorScopeContext { int contrast[4]; int fade[4]; double zoom; + int swap; + int mirror; unsigned prev_x, prev_y; AVRational frame_rate; } AudioVectorScopeContext; @@ -99,6 +101,12 @@ static const AVOption avectorscope_options[] = { { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" }, { "cbrt", "cube root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" }, { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" }, + { "swap", "swap x axis with y axis", OFFSET(swap), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "mirror", "mirror axis", OFFSET(mirror), AV_OPT_TYPE_INT, {.i64=2}, 0, 3, FLAGS, "mirror" }, + { "none", "no mirror", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mirror" }, + { "x", "mirror x", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mirror" }, + { "y", "mirror y", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mirror" }, + { "xy", "mirror both", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "mirror" }, { NULL } }; @@ -316,6 +324,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) break; } + if (s->mirror & 1) + src[0] = -src[0]; + + if (s->mirror & 2) + src[1] = -src[1]; + + if (s->swap) + FFSWAP(float, src[0], src[1]);; + if (s->mode == LISSAJOUS) { x = ((src[1] - src[0]) * zoom / 2 + 1) * hw; y = (1.0 - (src[0] + src[1]) * zoom / 2) * hh; diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index f0f849b32..ea75467a7 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -19,7 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/atomic.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/buffer.h" @@ -33,6 +32,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/samplefmt.h" +#include "libavutil/thread.h" #define FF_INTERNAL_FIELDS 1 #include "framequeue.h" @@ -183,10 +183,12 @@ void avfilter_link_free(AVFilterLink **link) av_freep(link); } +#if FF_API_FILTER_GET_SET int avfilter_link_get_channels(AVFilterLink *link) { return link->channels; } +#endif void ff_filter_set_ready(AVFilterContext *filter, unsigned priority) { @@ -576,10 +578,7 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha static AVFilter *first_filter; static AVFilter **last_filter = &first_filter; -#if !FF_API_NOCONST_GET_NAME -const -#endif -AVFilter *avfilter_get_by_name(const char *name) +const AVFilter *avfilter_get_by_name(const char *name) { const AVFilter *f = NULL; @@ -593,19 +592,26 @@ AVFilter *avfilter_get_by_name(const char *name) return NULL; } +static AVMutex filter_register_mutex = AV_MUTEX_INITIALIZER; + int avfilter_register(AVFilter *filter) { - AVFilter **f = last_filter; + AVFilter **f; /* the filter must select generic or internal exclusively */ av_assert0((filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) != AVFILTER_FLAG_SUPPORT_TIMELINE); - filter->next = NULL; + ff_mutex_lock(&filter_register_mutex); + f = last_filter; - while(*f || avpriv_atomic_ptr_cas((void * volatile *)f, NULL, filter)) + while (*f) f = &(*f)->next; + *f = filter; + filter->next = NULL; last_filter = &filter->next; + ff_mutex_unlock(&filter_register_mutex); + return 0; } @@ -614,17 +620,6 @@ const AVFilter *avfilter_next(const AVFilter *prev) return prev ? prev->next : first_filter; } -#if FF_API_OLD_FILTER_REGISTER -AVFilter **av_filter_next(AVFilter **filter) -{ - return filter ? &(*filter)->next : &first_filter; -} - -void avfilter_uninit(void) -{ -} -#endif - int avfilter_pad_count(const AVFilterPad *pads) { int count; @@ -783,14 +778,6 @@ err: return NULL; } -#if FF_API_AVFILTER_OPEN -int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name) -{ - *filter_ctx = ff_filter_alloc(filter, inst_name); - return *filter_ctx ? 0 : AVERROR(ENOMEM); -} -#endif - static void free_link(AVFilterLink *link) { if (!link) @@ -939,13 +926,6 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, return count; } -#if FF_API_AVFILTER_INIT_FILTER -int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) -{ - return avfilter_init_str(filter, args); -} -#endif - int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) { int ret = 0; @@ -996,7 +976,7 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) return AVERROR(EINVAL); } -#if FF_API_OLD_FILTER_OPTS || FF_API_OLD_FILTER_OPTS_ERROR +#if FF_API_OLD_FILTER_OPTS_ERROR if ( !strcmp(filter->filter->name, "format") || !strcmp(filter->filter->name, "noformat") || !strcmp(filter->filter->name, "frei0r") || @@ -1056,14 +1036,6 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) while ((p = strchr(p, ':'))) *p++ = '|'; -#if FF_API_OLD_FILTER_OPTS - if (deprecated) - av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use " - "'|' to separate the list items.\n"); - - av_log(filter, AV_LOG_DEBUG, "compat: called with args=[%s]\n", copy); - ret = process_options(filter, &options, copy); -#else if (deprecated) { av_log(filter, AV_LOG_ERROR, "This syntax is deprecated. Use " "'|' to separate the list items ('%s' instead of '%s')\n", @@ -1072,7 +1044,6 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) } else { ret = process_options(filter, &options, copy); } -#endif av_freep(©); if (ret < 0) @@ -1570,7 +1541,7 @@ int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, return 0; if (link->status_in) min = FFMIN(min, ff_framequeue_queued_samples(&link->fifo)); - ret = take_samples(link, min, link->max_samples, &frame); + ret = take_samples(link, min, max, &frame); if (ret < 0) return ret; consume_update(link, frame); diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 73a723d58..62eed2168 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -647,10 +647,14 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, */ 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. @@ -680,12 +684,6 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha /** Initialize the filter system. Register all builtin filters. */ void avfilter_register_all(void); -#if FF_API_OLD_FILTER_REGISTER -/** Uninitialize the filter system. Unregister all filters. */ -attribute_deprecated -void avfilter_uninit(void); -#endif - /** * 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 @@ -705,10 +703,7 @@ int avfilter_register(AVFilter *filter); * @return the filter definition, if any matching one is registered. * NULL if none found. */ -#if !FF_API_NOCONST_GET_NAME -const -#endif -AVFilter *avfilter_get_by_name(const char *name); +const AVFilter *avfilter_get_by_name(const char *name); /** * Iterate over all registered filters. @@ -717,49 +712,6 @@ AVFilter *avfilter_get_by_name(const char *name); */ const AVFilter *avfilter_next(const AVFilter *prev); -#if FF_API_OLD_FILTER_REGISTER -/** - * If filter is NULL, returns a pointer to the first registered filter pointer, - * if filter is non-NULL, returns the next pointer after filter. - * If the returned pointer points to NULL, the last registered filter - * was already reached. - * @deprecated use avfilter_next() - */ -attribute_deprecated -AVFilter **av_filter_next(AVFilter **filter); -#endif - -#if FF_API_AVFILTER_OPEN -/** - * Create a filter instance. - * - * @param filter_ctx put here a pointer to the created filter context - * on success, NULL on failure - * @param filter the filter to create an instance of - * @param inst_name Name to give to the new instance. Can be NULL for none. - * @return >= 0 in case of success, a negative error code otherwise - * @deprecated use avfilter_graph_alloc_filter() instead - */ -attribute_deprecated -int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name); -#endif - - -#if FF_API_AVFILTER_INIT_FILTER -/** - * Initialize a filter. - * - * @param filter the filter to initialize - * @param args A string of parameters to use when initializing the filter. - * The format and meaning of this string varies by filter. - * @param opaque Any extra non-string data needed by the filter. The meaning - * of this parameter varies by filter. - * @return zero on success - */ -attribute_deprecated -int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque); -#endif - /** * Initialize a filter with the supplied parameters. * @@ -959,20 +911,6 @@ AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, */ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name); -#if FF_API_AVFILTER_OPEN -/** - * Add an existing filter instance to a filter graph. - * - * @param graphctx the filter graph - * @param filter the filter to be added - * - * @deprecated use avfilter_graph_alloc_filter() to allocate a filter in a - * filter graph - */ -attribute_deprecated -int avfilter_graph_add_filter(AVFilterGraph *graphctx, AVFilterContext *filter); -#endif - /** * Create and add a filter instance into an existing graph. * The filter instance is created from the filter filt and inited diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 4304c0684..4cc689240 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -28,6 +28,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" +#include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -42,17 +43,19 @@ #include "thread.h" #define OFFSET(x) offsetof(AVFilterGraph, x) -#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +#define F AV_OPT_FLAG_FILTERING_PARAM +#define V AV_OPT_FLAG_VIDEO_PARAM +#define A AV_OPT_FLAG_AUDIO_PARAM static const AVOption filtergraph_options[] = { { "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, - { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" }, - { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = FLAGS, .unit = "thread_type" }, + { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, F|V|A, "thread_type" }, + { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = F|V|A, .unit = "thread_type" }, { "threads", "Maximum number of threads", OFFSET(nb_threads), - AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, F|V|A }, {"scale_sws_opts" , "default scale filter options" , OFFSET(scale_sws_opts) , - AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, + AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|V }, {"aresample_swr_opts" , "default aresample filter options" , OFFSET(aresample_swr_opts) , - AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, + AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|A }, { NULL }, }; @@ -136,23 +139,6 @@ void avfilter_graph_free(AVFilterGraph **graph) av_freep(graph); } -#if FF_API_AVFILTER_OPEN -int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter) -{ - AVFilterContext **filters = av_realloc(graph->filters, - sizeof(*filters) * (graph->nb_filters + 1)); - if (!filters) - return AVERROR(ENOMEM); - - graph->filters = filters; - graph->filters[graph->nb_filters++] = filter; - - filter->graph = graph; - - return 0; -} -#endif - int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx) @@ -280,6 +266,27 @@ static int graph_config_links(AVFilterGraph *graph, AVClass *log_ctx) return 0; } +static int graph_check_links(AVFilterGraph *graph, AVClass *log_ctx) +{ + AVFilterContext *f; + AVFilterLink *l; + unsigned i, j; + int ret; + + for (i = 0; i < graph->nb_filters; i++) { + f = graph->filters[i]; + for (j = 0; j < f->nb_outputs; j++) { + l = f->outputs[j]; + if (l->type == AVMEDIA_TYPE_VIDEO) { + ret = av_image_check_size2(l->w, l->h, INT64_MAX, l->format, 0, f); + if (ret < 0) + return ret; + } + } + } + return 0; +} + AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name) { int i; @@ -509,9 +516,8 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) if (convert_needed) { AVFilterContext *convert; - AVFilter *filter; + const AVFilter *filter; AVFilterLink *inlink, *outlink; - char scale_args[256]; char inst_name[30]; if (graph->disable_auto_convert) { @@ -548,10 +554,6 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) snprintf(inst_name, sizeof(inst_name), "auto_resampler_%d", resampler_count++); - scale_args[0] = '\0'; - if (graph->aresample_swr_opts) - snprintf(scale_args, sizeof(scale_args), "%s", - graph->aresample_swr_opts); if ((ret = avfilter_graph_create_filter(&convert, filter, inst_name, graph->aresample_swr_opts, NULL, graph)) < 0) @@ -1235,7 +1237,7 @@ static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx) for (j = 0; j < f->nb_inputs; j++) { AVFilterLink *link = f->inputs[j]; AVFilterContext *fifo_ctx; - AVFilter *fifo; + const AVFilter *fifo; char name[32]; if (!link->dstpad->needs_fifo) @@ -1273,6 +1275,8 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) return ret; if ((ret = graph_config_links(graphctx, log_ctx))) return ret; + if ((ret = graph_check_links(graphctx, log_ctx))) + return ret; if ((ret = graph_config_pointers(graphctx, log_ctx))) return ret; diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index ad5aedd5f..cd56f8ca4 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -304,14 +304,6 @@ static const AVOption buffer_options[] = { { "video_size", NULL, OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, .flags = V }, { "height", NULL, OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, { "pix_fmt", NULL, OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, .min = AV_PIX_FMT_NONE, .max = INT_MAX, .flags = V }, -#if FF_API_OLD_FILTER_OPTS - /* those 4 are for compatibility with the old option passing system where each filter - * did its own parsing */ - { "time_base_num", "deprecated, do not use", OFFSET(time_base.num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, - { "time_base_den", "deprecated, do not use", OFFSET(time_base.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, - { "sar_num", "deprecated, do not use", OFFSET(pixel_aspect.num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, - { "sar_den", "deprecated, do not use", OFFSET(pixel_aspect.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, -#endif { "sar", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, { "pixel_aspect", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, diff --git a/libavfilter/deshake.h b/libavfilter/deshake.h index 5e25bb3a7..406cbab2f 100644 --- a/libavfilter/deshake.h +++ b/libavfilter/deshake.h @@ -26,9 +26,6 @@ #include "avfilter.h" #include "transform.h" #include "libavutil/pixelutils.h" -#if CONFIG_OPENCL -#include "libavutil/opencl.h" -#endif enum SearchMethod { @@ -53,24 +50,6 @@ typedef struct Transform { double zoom; ///< Zoom percentage } Transform; -#if CONFIG_OPENCL - -typedef struct DeshakeOpenclContext { - cl_command_queue command_queue; - cl_program program; - cl_kernel kernel_luma; - cl_kernel kernel_chroma; - int in_plane_size[8]; - int out_plane_size[8]; - int plane_num; - cl_mem cl_inbuf; - size_t cl_inbuf_size; - cl_mem cl_outbuf; - size_t cl_outbuf_size; -} DeshakeOpenclContext; - -#endif - #define MAX_R 64 typedef struct DeshakeContext { @@ -96,9 +75,6 @@ typedef struct DeshakeContext { int cy; char *filename; ///< Motion search detailed log filename int opencl; -#if CONFIG_OPENCL - DeshakeOpenclContext opencl_ctx; -#endif int (* transform)(AVFilterContext *ctx, int width, int height, int cw, int ch, const float *matrix_y, const float *matrix_uv, enum InterpolateMethod interpolate, enum FillMethod fill, AVFrame *in, AVFrame *out); diff --git a/libavfilter/deshake_opencl.c b/libavfilter/deshake_opencl.c deleted file mode 100644 index 877ec1dc0..000000000 --- a/libavfilter/deshake_opencl.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - * transform input video - */ - -#include "libavutil/common.h" -#include "libavutil/dict.h" -#include "libavutil/pixdesc.h" -#include "deshake_opencl.h" -#include "libavutil/opencl_internal.h" - -#define PLANE_NUM 3 -#define ROUND_TO_16(a) (((((a) - 1)/16)+1)*16) - -int ff_opencl_transform(AVFilterContext *ctx, - int width, int height, int cw, int ch, - const float *matrix_y, const float *matrix_uv, - enum InterpolateMethod interpolate, - enum FillMethod fill, AVFrame *in, AVFrame *out) -{ - int ret = 0; - cl_int status; - DeshakeContext *deshake = ctx->priv; - float4 packed_matrix_lu = {matrix_y[0], matrix_y[1], matrix_y[2], matrix_y[5]}; - float4 packed_matrix_ch = {matrix_uv[0], matrix_uv[1], matrix_uv[2], matrix_uv[5]}; - size_t global_worksize_lu[2] = {(size_t)ROUND_TO_16(width), (size_t)ROUND_TO_16(height)}; - size_t global_worksize_ch[2] = {(size_t)ROUND_TO_16(cw), (size_t)(2*ROUND_TO_16(ch))}; - size_t local_worksize[2] = {16, 16}; - FFOpenclParam param_lu = {0}; - FFOpenclParam param_ch = {0}; - param_lu.ctx = param_ch.ctx = ctx; - param_lu.kernel = deshake->opencl_ctx.kernel_luma; - param_ch.kernel = deshake->opencl_ctx.kernel_chroma; - - if ((unsigned int)interpolate > INTERPOLATE_BIQUADRATIC) { - av_log(ctx, AV_LOG_ERROR, "Selected interpolate method is invalid\n"); - return AVERROR(EINVAL); - } - ret = avpriv_opencl_set_parameter(¶m_lu, - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(packed_matrix_lu), - FF_OPENCL_PARAM_INFO(interpolate), - FF_OPENCL_PARAM_INFO(fill), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(height), - FF_OPENCL_PARAM_INFO(width), - NULL); - if (ret < 0) - return ret; - ret = avpriv_opencl_set_parameter(¶m_ch, - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(packed_matrix_ch), - FF_OPENCL_PARAM_INFO(interpolate), - FF_OPENCL_PARAM_INFO(fill), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(in->linesize[1]), - FF_OPENCL_PARAM_INFO(out->linesize[1]), - FF_OPENCL_PARAM_INFO(height), - FF_OPENCL_PARAM_INFO(width), - FF_OPENCL_PARAM_INFO(ch), - FF_OPENCL_PARAM_INFO(cw), - NULL); - if (ret < 0) - return ret; - status = clEnqueueNDRangeKernel(deshake->opencl_ctx.command_queue, - deshake->opencl_ctx.kernel_luma, 2, NULL, - global_worksize_lu, local_worksize, 0, NULL, NULL); - status |= clEnqueueNDRangeKernel(deshake->opencl_ctx.command_queue, - deshake->opencl_ctx.kernel_chroma, 2, NULL, - global_worksize_ch, local_worksize, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - ret = av_opencl_buffer_read_image(out->data, deshake->opencl_ctx.out_plane_size, - deshake->opencl_ctx.plane_num, deshake->opencl_ctx.cl_outbuf, - deshake->opencl_ctx.cl_outbuf_size); - if (ret < 0) - return ret; - return ret; -} - -int ff_opencl_deshake_init(AVFilterContext *ctx) -{ - int ret = 0; - DeshakeContext *deshake = ctx->priv; - ret = av_opencl_init(NULL); - if (ret < 0) - return ret; - deshake->opencl_ctx.plane_num = PLANE_NUM; - deshake->opencl_ctx.command_queue = av_opencl_get_command_queue(); - if (!deshake->opencl_ctx.command_queue) { - av_log(ctx, AV_LOG_ERROR, "Unable to get OpenCL command queue in filter 'deshake'\n"); - return AVERROR(EINVAL); - } - deshake->opencl_ctx.program = av_opencl_compile("avfilter_transform", NULL); - if (!deshake->opencl_ctx.program) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to compile program 'avfilter_transform'\n"); - return AVERROR(EINVAL); - } - if (!deshake->opencl_ctx.kernel_luma) { - deshake->opencl_ctx.kernel_luma = clCreateKernel(deshake->opencl_ctx.program, - "avfilter_transform_luma", &ret); - if (ret != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'avfilter_transform_luma'\n"); - return AVERROR(EINVAL); - } - } - if (!deshake->opencl_ctx.kernel_chroma) { - deshake->opencl_ctx.kernel_chroma = clCreateKernel(deshake->opencl_ctx.program, - "avfilter_transform_chroma", &ret); - if (ret != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'avfilter_transform_chroma'\n"); - return AVERROR(EINVAL); - } - } - return ret; -} - -void ff_opencl_deshake_uninit(AVFilterContext *ctx) -{ - DeshakeContext *deshake = ctx->priv; - av_opencl_buffer_release(&deshake->opencl_ctx.cl_inbuf); - av_opencl_buffer_release(&deshake->opencl_ctx.cl_outbuf); - clReleaseKernel(deshake->opencl_ctx.kernel_luma); - clReleaseKernel(deshake->opencl_ctx.kernel_chroma); - clReleaseProgram(deshake->opencl_ctx.program); - deshake->opencl_ctx.command_queue = NULL; - av_opencl_uninit(); -} - -int ff_opencl_deshake_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out) -{ - int ret = 0; - AVFilterLink *link = ctx->inputs[0]; - DeshakeContext *deshake = ctx->priv; - const int hshift = av_pix_fmt_desc_get(link->format)->log2_chroma_h; - int chroma_height = AV_CEIL_RSHIFT(link->h, hshift); - - if ((!deshake->opencl_ctx.cl_inbuf) || (!deshake->opencl_ctx.cl_outbuf)) { - deshake->opencl_ctx.in_plane_size[0] = (in->linesize[0] * in->height); - deshake->opencl_ctx.in_plane_size[1] = (in->linesize[1] * chroma_height); - deshake->opencl_ctx.in_plane_size[2] = (in->linesize[2] * chroma_height); - deshake->opencl_ctx.out_plane_size[0] = (out->linesize[0] * out->height); - deshake->opencl_ctx.out_plane_size[1] = (out->linesize[1] * chroma_height); - deshake->opencl_ctx.out_plane_size[2] = (out->linesize[2] * chroma_height); - deshake->opencl_ctx.cl_inbuf_size = deshake->opencl_ctx.in_plane_size[0] + - deshake->opencl_ctx.in_plane_size[1] + - deshake->opencl_ctx.in_plane_size[2]; - deshake->opencl_ctx.cl_outbuf_size = deshake->opencl_ctx.out_plane_size[0] + - deshake->opencl_ctx.out_plane_size[1] + - deshake->opencl_ctx.out_plane_size[2]; - if (!deshake->opencl_ctx.cl_inbuf) { - ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_inbuf, - deshake->opencl_ctx.cl_inbuf_size, - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - } - if (!deshake->opencl_ctx.cl_outbuf) { - ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_outbuf, - deshake->opencl_ctx.cl_outbuf_size, - CL_MEM_READ_WRITE, NULL); - if (ret < 0) - return ret; - } - } - ret = av_opencl_buffer_write_image(deshake->opencl_ctx.cl_inbuf, - deshake->opencl_ctx.cl_inbuf_size, - 0, in->data,deshake->opencl_ctx.in_plane_size, - deshake->opencl_ctx.plane_num); - return ret; -} diff --git a/libavfilter/deshake_opencl.h b/libavfilter/deshake_opencl.h deleted file mode 100644 index f3d96dc4e..000000000 --- a/libavfilter/deshake_opencl.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_DESHAKE_OPENCL_H -#define AVFILTER_DESHAKE_OPENCL_H - -#include "deshake.h" - -typedef struct float4 { - float x; - float y; - float z; - float w; -} float4; - -int ff_opencl_deshake_init(AVFilterContext *ctx); - -void ff_opencl_deshake_uninit(AVFilterContext *ctx); - -int ff_opencl_deshake_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - -int ff_opencl_transform(AVFilterContext *ctx, - int width, int height, int cw, int ch, - const float *matrix_y, const float *matrix_uv, - enum InterpolateMethod interpolate, - enum FillMethod fill, AVFrame *in, AVFrame *out); - -#endif /* AVFILTER_DESHAKE_OPENCL_H */ diff --git a/libavfilter/deshake_opencl_kernel.h b/libavfilter/deshake_opencl_kernel.h deleted file mode 100644 index dd45d6f60..000000000 --- a/libavfilter/deshake_opencl_kernel.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_DESHAKE_OPENCL_KERNEL_H -#define AVFILTER_DESHAKE_OPENCL_KERNEL_H - -#include "libavutil/opencl.h" - -const char *ff_kernel_deshake_opencl = AV_OPENCL_KERNEL( -inline unsigned char pixel(global const unsigned char *src, int x, int y, - int w, int h,int stride, unsigned char def) -{ - return (x < 0 || y < 0 || x >= w || y >= h) ? def : src[x + y * stride]; -} - -unsigned char interpolate_nearest(float x, float y, global const unsigned char *src, - int width, int height, int stride, unsigned char def) -{ - return pixel(src, (int)(x + 0.5f), (int)(y + 0.5f), width, height, stride, def); -} - -unsigned char interpolate_bilinear(float x, float y, global const unsigned char *src, - int width, int height, int stride, unsigned char def) -{ - int x_c, x_f, y_c, y_f; - int v1, v2, v3, v4; - x_f = (int)x; - y_f = (int)y; - x_c = x_f + 1; - y_c = y_f + 1; - - if (x_f < -1 || x_f > width || y_f < -1 || y_f > height) { - return def; - } else { - v4 = pixel(src, x_f, y_f, width, height, stride, def); - v2 = pixel(src, x_c, y_f, width, height, stride, def); - v3 = pixel(src, x_f, y_c, width, height, stride, def); - v1 = pixel(src, x_c, y_c, width, height, stride, def); - return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) + - v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y))); - } -} - -unsigned char interpolate_biquadratic(float x, float y, global const unsigned char *src, - int width, int height, int stride, unsigned char def) -{ - int x_c, x_f, y_c, y_f; - unsigned char v1, v2, v3, v4; - float f1, f2, f3, f4; - x_f = (int)x; - y_f = (int)y; - x_c = x_f + 1; - y_c = y_f + 1; - - if (x_f < - 1 || x_f > width || y_f < -1 || y_f > height) - return def; - else { - v4 = pixel(src, x_f, y_f, width, height, stride, def); - v2 = pixel(src, x_c, y_f, width, height, stride, def); - v3 = pixel(src, x_f, y_c, width, height, stride, def); - v1 = pixel(src, x_c, y_c, width, height, stride, def); - - f1 = 1 - sqrt((x_c - x) * (y_c - y)); - f2 = 1 - sqrt((x_c - x) * (y - y_f)); - f3 = 1 - sqrt((x - x_f) * (y_c - y)); - f4 = 1 - sqrt((x - x_f) * (y - y_f)); - return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4); - } -} - -inline const float clipf(float a, float amin, float amax) -{ - if (a < amin) return amin; - else if (a > amax) return amax; - else return a; -} - -inline int mirror(int v, int m) -{ - while ((unsigned)v > (unsigned)m) { - v = -v; - if (v < 0) - v += 2 * m; - } - return v; -} - -kernel void avfilter_transform_luma(global unsigned char *src, - global unsigned char *dst, - float4 matrix, - int interpolate, - int fill, - int src_stride_lu, - int dst_stride_lu, - int height, - int width) -{ - int x = get_global_id(0); - int y = get_global_id(1); - int idx_dst = y * dst_stride_lu + x; - unsigned char def = 0; - float x_s = x * matrix.x + y * matrix.y + matrix.z; - float y_s = x * (-matrix.y) + y * matrix.x + matrix.w; - - if (x < width && y < height) { - switch (fill) { - case 0: //FILL_BLANK - def = 0; - break; - case 1: //FILL_ORIGINAL - def = src[y*src_stride_lu + x]; - break; - case 2: //FILL_CLAMP - y_s = clipf(y_s, 0, height - 1); - x_s = clipf(x_s, 0, width - 1); - def = src[(int)y_s * src_stride_lu + (int)x_s]; - break; - case 3: //FILL_MIRROR - y_s = mirror(y_s, height - 1); - x_s = mirror(x_s, width - 1); - def = src[(int)y_s * src_stride_lu + (int)x_s]; - break; - } - switch (interpolate) { - case 0: //INTERPOLATE_NEAREST - dst[idx_dst] = interpolate_nearest(x_s, y_s, src, width, height, src_stride_lu, def); - break; - case 1: //INTERPOLATE_BILINEAR - dst[idx_dst] = interpolate_bilinear(x_s, y_s, src, width, height, src_stride_lu, def); - break; - case 2: //INTERPOLATE_BIQUADRATIC - dst[idx_dst] = interpolate_biquadratic(x_s, y_s, src, width, height, src_stride_lu, def); - break; - default: - return; - } - } -} - -kernel void avfilter_transform_chroma(global unsigned char *src, - global unsigned char *dst, - float4 matrix, - int interpolate, - int fill, - int src_stride_lu, - int dst_stride_lu, - int src_stride_ch, - int dst_stride_ch, - int height, - int width, - int ch, - int cw) -{ - - int x = get_global_id(0); - int y = get_global_id(1); - int pad_ch = get_global_size(1)>>1; - global unsigned char *dst_u = dst + height * dst_stride_lu; - global unsigned char *src_u = src + height * src_stride_lu; - global unsigned char *dst_v = dst_u + ch * dst_stride_ch; - global unsigned char *src_v = src_u + ch * src_stride_ch; - src = y < pad_ch ? src_u : src_v; - dst = y < pad_ch ? dst_u : dst_v; - y = select(y - pad_ch, y, y < pad_ch); - float x_s = x * matrix.x + y * matrix.y + matrix.z; - float y_s = x * (-matrix.y) + y * matrix.x + matrix.w; - int idx_dst = y * dst_stride_ch + x; - unsigned char def; - - if (x < cw && y < ch) { - switch (fill) { - case 0: //FILL_BLANK - def = 0; - break; - case 1: //FILL_ORIGINAL - def = src[y*src_stride_ch + x]; - break; - case 2: //FILL_CLAMP - y_s = clipf(y_s, 0, ch - 1); - x_s = clipf(x_s, 0, cw - 1); - def = src[(int)y_s * src_stride_ch + (int)x_s]; - break; - case 3: //FILL_MIRROR - y_s = mirror(y_s, ch - 1); - x_s = mirror(x_s, cw - 1); - def = src[(int)y_s * src_stride_ch + (int)x_s]; - break; - } - switch (interpolate) { - case 0: //INTERPOLATE_NEAREST - dst[idx_dst] = interpolate_nearest(x_s, y_s, src, cw, ch, src_stride_ch, def); - break; - case 1: //INTERPOLATE_BILINEAR - dst[idx_dst] = interpolate_bilinear(x_s, y_s, src, cw, ch, src_stride_ch, def); - break; - case 2: //INTERPOLATE_BIQUADRATIC - dst[idx_dst] = interpolate_biquadratic(x_s, y_s, src, cw, ch, src_stride_ch, def); - break; - default: - return; - } - } -} -); - -#endif /* AVFILTER_DESHAKE_OPENCL_KERNEL_H */ diff --git a/libavfilter/formats.c b/libavfilter/formats.c index d4de86223..20a2c8971 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -72,7 +72,7 @@ do { for (j = 0; j < b->nb; j++) \ if (a->fmts[i] == b->fmts[j]) { \ if(k >= FFMIN(a->nb, b->nb)){ \ - av_log(NULL, AV_LOG_ERROR, "Duplicate formats in avfilter_merge_formats() detected\n"); \ + av_log(NULL, AV_LOG_ERROR, "Duplicate formats in %s detected\n", __FUNCTION__); \ av_free(ret->fmts); \ av_free(ret); \ return NULL; \ diff --git a/libavfilter/framepool.c b/libavfilter/framepool.c index 42c0e5849..da2ac5cf6 100644 --- a/libavfilter/framepool.c +++ b/libavfilter/framepool.c @@ -71,7 +71,7 @@ FFFramePool *ff_frame_pool_video_init(AVBufferRef* (*alloc)(int size), pool->format = format; pool->align = align; - if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) { + if ((ret = av_image_check_size2(width, height, INT64_MAX, format, 0, NULL)) < 0) { goto fail; } diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c index 82d715750..da12c58a6 100644 --- a/libavfilter/framesync.c +++ b/libavfilter/framesync.c @@ -406,7 +406,7 @@ int ff_framesync_dualinput_get_writable(FFFrameSync *fs, AVFrame **f0, AVFrame * ret = ff_inlink_make_frame_writable(fs->parent->inputs[0], f0); if (ret < 0) { av_frame_free(f0); - av_frame_free(f1); + *f1 = NULL; return ret; } return 0; diff --git a/libavfilter/framesync.h b/libavfilter/framesync.h index 9fdc4d1ae..abf3bf552 100644 --- a/libavfilter/framesync.h +++ b/libavfilter/framesync.h @@ -286,6 +286,9 @@ int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent); * @param f0 used to return the main frame * @param f1 used to return the second frame, or NULL if disabled * @return >=0 for success or AVERROR code + * @note The frame returned in f0 belongs to the caller (get = 1 in + * ff_framesync_get_frame()) while the frame returned in f1 is still owned + * by the framesync structure. */ int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1); diff --git a/libavfilter/graphparser.c b/libavfilter/graphparser.c index 1405926bf..d92b5360a 100644 --- a/libavfilter/graphparser.c +++ b/libavfilter/graphparser.c @@ -96,7 +96,7 @@ static char *parse_link_name(const char **buf, void *log_ctx) static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int index, const char *name, const char *args, void *log_ctx) { - AVFilter *filt; + const AVFilter *filt; char name2[30]; const char *inst_name = NULL, *filt_name = NULL; char *tmp_args = NULL; diff --git a/libavfilter/hflip.h b/libavfilter/hflip.h new file mode 100644 index 000000000..204090dbb --- /dev/null +++ b/libavfilter/hflip.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007 Benoit Fouet + * Copyright (c) 2010 Stefano Sabatini + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_HFLIP_H +#define AVFILTER_HFLIP_H + +#include "avfilter.h" + +typedef struct FlipContext { + const AVClass *class; + int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes + int planewidth[4]; ///< width of each plane + int planeheight[4]; ///< height of each plane + + void (*flip_line[4])(const uint8_t *src, uint8_t *dst, int w); +} FlipContext; + +int ff_hflip_init(FlipContext *s, int step[4], int nb_planes); +void ff_hflip_init_x86(FlipContext *s, int step[4], int nb_planes); + +#endif /* AVFILTER_HFLIP_H */ diff --git a/libavfilter/interlace.h b/libavfilter/interlace.h index 90a0198bd..b41f0d570 100644 --- a/libavfilter/interlace.h +++ b/libavfilter/interlace.h @@ -62,6 +62,7 @@ typedef struct InterlaceContext { ptrdiff_t mref, ptrdiff_t pref, int clip_max); } InterlaceContext; -void ff_interlace_init_x86(InterlaceContext *interlace); +void ff_interlace_init(InterlaceContext *interlace, int depth); +void ff_interlace_init_x86(InterlaceContext *interlace, int depth); #endif /* AVFILTER_INTERLACE_H */ diff --git a/libavfilter/opencl.c b/libavfilter/opencl.c new file mode 100644 index 000000000..37afc41f8 --- /dev/null +++ b/libavfilter/opencl.c @@ -0,0 +1,278 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/hwcontext.h" +#include "libavutil/hwcontext_opencl.h" +#include "libavutil/mem.h" + +#include "avfilter.h" +#include "formats.h" +#include "opencl.h" + +int ff_opencl_filter_query_formats(AVFilterContext *avctx) +{ + const static enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_OPENCL, + AV_PIX_FMT_NONE, + }; + AVFilterFormats *formats; + + formats = ff_make_format_list(pix_fmts); + if (!formats) + return AVERROR(ENOMEM); + + return ff_set_common_formats(avctx, formats); +} + +static int opencl_filter_set_device(AVFilterContext *avctx, + AVBufferRef *device) +{ + OpenCLFilterContext *ctx = avctx->priv; + + av_buffer_unref(&ctx->device_ref); + + ctx->device_ref = av_buffer_ref(device); + if (!ctx->device_ref) + return AVERROR(ENOMEM); + + ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; + ctx->hwctx = ctx->device->hwctx; + + return 0; +} + +int ff_opencl_filter_config_input(AVFilterLink *inlink) +{ + AVFilterContext *avctx = inlink->dst; + OpenCLFilterContext *ctx = avctx->priv; + AVHWFramesContext *input_frames; + int err; + + if (!inlink->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a " + "hardware frames context on the input.\n"); + return AVERROR(EINVAL); + } + + // Extract the device and default output format from the first input. + if (avctx->inputs[0] != inlink) + return 0; + + input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + if (input_frames->format != AV_PIX_FMT_OPENCL) + return AVERROR(EINVAL); + + err = opencl_filter_set_device(avctx, input_frames->device_ref); + if (err < 0) + return err; + + // Default output parameters match input parameters. + if (ctx->output_format == AV_PIX_FMT_NONE) + ctx->output_format = input_frames->sw_format; + if (!ctx->output_width) + ctx->output_width = inlink->w; + if (!ctx->output_height) + ctx->output_height = inlink->h; + + return 0; +} + +int ff_opencl_filter_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + OpenCLFilterContext *ctx = avctx->priv; + AVBufferRef *output_frames_ref = NULL; + AVHWFramesContext *output_frames; + int err; + + av_buffer_unref(&outlink->hw_frames_ctx); + + if (!ctx->device_ref) { + if (!avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires an " + "OpenCL device.\n"); + return AVERROR(EINVAL); + } + + err = opencl_filter_set_device(avctx, avctx->hw_device_ctx); + if (err < 0) + return err; + } + + output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); + if (!output_frames_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + output_frames = (AVHWFramesContext*)output_frames_ref->data; + + output_frames->format = AV_PIX_FMT_OPENCL; + output_frames->sw_format = ctx->output_format; + output_frames->width = ctx->output_width; + output_frames->height = ctx->output_height; + + err = av_hwframe_ctx_init(output_frames_ref); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialise output " + "frames: %d.\n", err); + goto fail; + } + + outlink->hw_frames_ctx = output_frames_ref; + outlink->w = ctx->output_width; + outlink->h = ctx->output_height; + + return 0; +fail: + av_buffer_unref(&output_frames_ref); + return err; +} + +int ff_opencl_filter_init(AVFilterContext *avctx) +{ + OpenCLFilterContext *ctx = avctx->priv; + + ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +void ff_opencl_filter_uninit(AVFilterContext *avctx) +{ + OpenCLFilterContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->program) { + cle = clReleaseProgram(ctx->program); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "program: %d.\n", cle); + } + + av_buffer_unref(&ctx->device_ref); +} + +int ff_opencl_filter_load_program(AVFilterContext *avctx, + const char **program_source_array, + int nb_strings) +{ + OpenCLFilterContext *ctx = avctx->priv; + cl_int cle; + + ctx->program = clCreateProgramWithSource(ctx->hwctx->context, nb_strings, + program_source_array, + NULL, &cle); + if (!ctx->program) { + av_log(avctx, AV_LOG_ERROR, "Failed to create program: %d.\n", cle); + return AVERROR(EIO); + } + + cle = clBuildProgram(ctx->program, 1, &ctx->hwctx->device_id, + NULL, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to build program: %d.\n", cle); + + if (cle == CL_BUILD_PROGRAM_FAILURE) { + char *log; + size_t log_length; + + clGetProgramBuildInfo(ctx->program, ctx->hwctx->device_id, + CL_PROGRAM_BUILD_LOG, 0, NULL, &log_length); + + log = av_malloc(log_length); + if (log) { + cle = clGetProgramBuildInfo(ctx->program, + ctx->hwctx->device_id, + CL_PROGRAM_BUILD_LOG, + log_length, log, NULL); + if (cle == CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Build log:\n%s\n", log); + } + + av_free(log); + } + + clReleaseProgram(ctx->program); + ctx->program = NULL; + return AVERROR(EIO); + } + + return 0; +} + +int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx, + const char *filename) +{ + FILE *file; + char *src = NULL; + size_t pos, len, rb; + const char *src_const; + int err; + + file = fopen(filename, "r"); + if (!file) { + av_log(avctx, AV_LOG_ERROR, "Unable to open program " + "source file \"%s\".\n", filename); + return AVERROR(ENOENT); + } + + len = 1 << 16; + pos = 0; + + err = av_reallocp(&src, len); + if (err < 0) + goto fail; + + err = snprintf(src, len, "#line 1 \"%s\"\n", filename); + if (err < 0) { + err = AVERROR(errno); + goto fail; + } + if (err > len / 2) { + err = AVERROR(EINVAL); + goto fail; + } + pos = err; + + while (1) { + rb = fread(src + pos, 1, len - pos - 1, file); + if (rb == 0 && ferror(file)) { + err = AVERROR(EIO); + goto fail; + } + pos += rb; + if (pos < len) + break; + len <<= 1; + err = av_reallocp(&src, len); + if (err < 0) + goto fail; + } + src[pos] = 0; + + src_const = src; + + err = ff_opencl_filter_load_program(avctx, &src_const, 1); +fail: + fclose(file); + av_freep(&src); + return err; +} diff --git a/libavfilter/opencl.h b/libavfilter/opencl.h new file mode 100644 index 000000000..4d740c18a --- /dev/null +++ b/libavfilter/opencl.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 + */ + +#ifndef AVFILTER_OPENCL_H +#define AVFILTER_OPENCL_H + +#include "libavutil/buffer.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_opencl.h" +#include "libavutil/pixfmt.h" + +#include "avfilter.h" + +typedef struct OpenCLFilterContext { + const AVClass *class; + + AVBufferRef *device_ref; + AVHWDeviceContext *device; + AVOpenCLDeviceContext *hwctx; + + cl_program program; + + enum AVPixelFormat output_format; + int output_width; + int output_height; +} OpenCLFilterContext; + +/** + * Return that all inputs and outputs support only AV_PIX_FMT_OPENCL. + */ +int ff_opencl_filter_query_formats(AVFilterContext *avctx); + +/** + * Check that the input link contains a suitable hardware frames + * context and extract the device from it. + */ +int ff_opencl_filter_config_input(AVFilterLink *inlink); + +/** + * Create a suitable hardware frames context for the output. + */ +int ff_opencl_filter_config_output(AVFilterLink *outlink); + +/** + * Initialise an OpenCL filter context. + */ +int ff_opencl_filter_init(AVFilterContext *avctx); + +/** + * Uninitialise an OpenCL filter context. + */ +void ff_opencl_filter_uninit(AVFilterContext *avctx); + +/** + * Load a new OpenCL program from strings in memory. + * + * Creates a new program and compiles it for the current device. + * Will log any build errors if compilation fails. + */ +int ff_opencl_filter_load_program(AVFilterContext *avctx, + const char **program_source_array, + int nb_strings); + +/** + * Load a new OpenCL program from a file. + * + * Same as ff_opencl_filter_load_program(), but from a file. + */ +int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx, + const char *filename); + +#endif /* AVFILTER_OPENCL_H */ diff --git a/libavfilter/opencl/overlay.cl b/libavfilter/opencl/overlay.cl new file mode 100644 index 000000000..8c783d0ed --- /dev/null +++ b/libavfilter/opencl/overlay.cl @@ -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 + */ + +__kernel void overlay_no_alpha(__write_only image2d_t dst, + __read_only image2d_t main, + __read_only image2d_t overlay, + int x_position, + int y_position) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + + int2 overlay_size = get_image_dim(overlay); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + if (loc.x < x_position || + loc.y < y_position || + loc.x >= overlay_size.x + x_position || + loc.y >= overlay_size.y + y_position) { + float4 val = read_imagef(main, sampler, loc); + write_imagef(dst, loc, val); + } else { + int2 loc_overlay = (int2)(x_position, y_position); + float4 val = read_imagef(overlay, sampler, loc - loc_overlay); + write_imagef(dst, loc, val); + } +} + +__kernel void overlay_internal_alpha(__write_only image2d_t dst, + __read_only image2d_t main, + __read_only image2d_t overlay, + int x_position, + int y_position) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + + int2 overlay_size = get_image_dim(overlay); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + if (loc.x < x_position || + loc.y < y_position || + loc.x >= overlay_size.x + x_position || + loc.y >= overlay_size.y + y_position) { + float4 val = read_imagef(main, sampler, loc); + write_imagef(dst, loc, val); + } else { + int2 loc_overlay = (int2)(x_position, y_position); + float4 in_main = read_imagef(main, sampler, loc); + float4 in_overlay = read_imagef(overlay, sampler, loc - loc_overlay); + float4 val = in_overlay * in_overlay.w + in_main * (1.0f - in_overlay.w); + write_imagef(dst, loc, val); + } +} + +__kernel void overlay_external_alpha(__write_only image2d_t dst, + __read_only image2d_t main, + __read_only image2d_t overlay, + __read_only image2d_t alpha, + int x_position, + int y_position, + int alpha_adj_x, + int alpha_adj_y) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + + int2 overlay_size = get_image_dim(overlay); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + if (loc.x < x_position || + loc.y < y_position || + loc.x >= overlay_size.x + x_position || + loc.y >= overlay_size.y + y_position) { + float4 val = read_imagef(main, sampler, loc); + write_imagef(dst, loc, val); + } else { + int2 loc_overlay = (int2)(x_position, y_position); + float4 in_main = read_imagef(main, sampler, loc); + float4 in_overlay = read_imagef(overlay, sampler, loc - loc_overlay); + + int2 loc_alpha = (int2)(loc.x * alpha_adj_x, + loc.y * alpha_adj_y) - loc_overlay; + float4 in_alpha = read_imagef(alpha, sampler, loc_alpha); + + float4 val = in_overlay * in_alpha.x + in_main * (1.0f - in_alpha.x); + write_imagef(dst, loc, val); + } +} diff --git a/libavfilter/opencl/unsharp.cl b/libavfilter/opencl/unsharp.cl new file mode 100644 index 000000000..e629834e5 --- /dev/null +++ b/libavfilter/opencl/unsharp.cl @@ -0,0 +1,99 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +__kernel void unsharp_global(__write_only image2d_t dst, + __read_only image2d_t src, + int size_x, + int size_y, + float amount, + __constant float *coef_matrix) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + int2 centre = (int2)(size_x / 2, size_y / 2); + + float4 val = read_imagef(src, sampler, loc); + float4 sum = 0.0f; + int x, y; + + for (y = 0; y < size_y; y++) { + for (x = 0; x < size_x; x++) { + int2 pos = loc + (int2)(x, y) - centre; + sum += coef_matrix[y * size_x + x] * + read_imagef(src, sampler, pos); + } + } + + write_imagef(dst, loc, val + (val - sum) * amount); +} + +__kernel void unsharp_local(__write_only image2d_t dst, + __read_only image2d_t src, + int size_x, + int size_y, + float amount, + __constant float *coef_x, + __constant float *coef_y) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + int2 block = (int2)(get_group_id(0), get_group_id(1)) * 16; + int2 pos = (int2)(get_local_id(0), get_local_id(1)); + + __local float4 tmp[32][32]; + + int rad_x = size_x / 2; + int rad_y = size_y / 2; + int x, y; + + for (y = 0; y <= 1; y++) { + for (x = 0; x <= 1; x++) { + tmp[pos.y + 16 * y][pos.x + 16 * x] = + read_imagef(src, sampler, block + pos + (int2)(16 * x - 8, 16 * y - 8)); + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + float4 val = tmp[pos.y + 8][pos.x + 8]; + + float4 horiz[2]; + for (y = 0; y <= 1; y++) { + horiz[y] = 0.0f; + for (x = 0; x < size_x; x++) + horiz[y] += coef_x[x] * tmp[pos.y + y * 16][pos.x + 8 + x - rad_x]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for (y = 0; y <= 1; y++) { + tmp[pos.y + y * 16][pos.x + 8] = horiz[y]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + float4 sum = 0.0f; + for (y = 0; y < size_y; y++) + sum += coef_y[y] * tmp[pos.y + 8 + y - rad_y][pos.x + 8]; + + if (block.x + pos.x < get_image_width(dst) && + block.y + pos.y < get_image_height(dst)) + write_imagef(dst, block + pos, val + (val - sum) * amount); +} diff --git a/libavfilter/opencl_allkernels.c b/libavfilter/opencl_allkernels.c deleted file mode 100644 index 6d80fa859..000000000 --- a/libavfilter/opencl_allkernels.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "opencl_allkernels.h" -#if CONFIG_OPENCL -#include "libavutil/opencl.h" -#include "deshake_opencl_kernel.h" -#include "unsharp_opencl_kernel.h" -#endif - -#define OPENCL_REGISTER_KERNEL_CODE(X, x) \ - { \ - if (CONFIG_##X##_FILTER) { \ - av_opencl_register_kernel_code(ff_kernel_##x##_opencl); \ - } \ - } - -void ff_opencl_register_filter_kernel_code_all(void) -{ - #if CONFIG_OPENCL - OPENCL_REGISTER_KERNEL_CODE(DESHAKE, deshake); - OPENCL_REGISTER_KERNEL_CODE(UNSHARP, unsharp); - #endif -} diff --git a/libavfilter/avfiltergraph.h b/libavfilter/opencl_source.h similarity index 78% rename from libavfilter/avfiltergraph.h rename to libavfilter/opencl_source.h index b31d581ca..23cdfc6ac 100644 --- a/libavfilter/avfiltergraph.h +++ b/libavfilter/opencl_source.h @@ -1,7 +1,4 @@ /* - * Filter graphs - * copyright (c) 2007 Bobby Bingham - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -19,10 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_AVFILTERGRAPH_H -#define AVFILTER_AVFILTERGRAPH_H +#ifndef AVFILTER_OPENCL_SOURCE_H +#define AVFILTER_OPENCL_SOURCE_H -#include "avfilter.h" -#include "libavutil/log.h" +extern const char *ff_opencl_source_overlay; +extern const char *ff_opencl_source_unsharp; -#endif /* AVFILTER_AVFILTERGRAPH_H */ +#endif /* AVFILTER_OPENCL_SOURCE_H */ diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c index 567dd4c17..7e37c73ca 100644 --- a/libavfilter/pthread.c +++ b/libavfilter/pthread.c @@ -85,10 +85,6 @@ int ff_graph_thread_init(AVFilterGraph *graph) { int ret; -#if HAVE_W32THREADS - w32thread_init(); -#endif - if (graph->nb_threads == 1) { graph->thread_type = 0; return 0; diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c new file mode 100644 index 000000000..f32b46dcc --- /dev/null +++ b/libavfilter/qsvvpp.c @@ -0,0 +1,730 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * Intel Quick Sync Video VPP base function + */ + +#include "libavutil/common.h" +#include "libavutil/mathematics.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_qsv.h" +#include "libavutil/time.h" +#include "libavutil/pixdesc.h" + +#include "internal.h" +#include "qsvvpp.h" +#include "video.h" + +#define IS_VIDEO_MEMORY(mode) (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \ + MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)) +#define IS_OPAQUE_MEMORY(mode) (mode & MFX_MEMTYPE_OPAQUE_FRAME) +#define IS_SYSTEM_MEMORY(mode) (mode & MFX_MEMTYPE_SYSTEM_MEMORY) + +typedef struct QSVFrame { + AVFrame *frame; + mfxFrameSurface1 *surface; + mfxFrameSurface1 surface_internal; /* for system memory */ + struct QSVFrame *next; +} QSVFrame; + +/* abstract struct for all QSV filters */ +struct QSVVPPContext { + mfxSession session; + int (*filter_frame) (AVFilterLink *outlink, AVFrame *frame);/* callback */ + enum AVPixelFormat out_sw_format; /* Real output format */ + mfxVideoParam vpp_param; + mfxFrameInfo *frame_infos; /* frame info for each input */ + + /* members related to the input/output surface */ + int in_mem_mode; + int out_mem_mode; + QSVFrame *in_frame_list; + QSVFrame *out_frame_list; + int nb_surface_ptrs_in; + int nb_surface_ptrs_out; + mfxFrameSurface1 **surface_ptrs_in; + mfxFrameSurface1 **surface_ptrs_out; + + /* MFXVPP extern parameters */ + mfxExtOpaqueSurfaceAlloc opaque_alloc; + mfxExtBuffer **ext_buffers; + int nb_ext_buffers; +}; + +static const mfxHandleType handle_types[] = { + MFX_HANDLE_VA_DISPLAY, + MFX_HANDLE_D3D9_DEVICE_MANAGER, + MFX_HANDLE_D3D11_DEVICE, +}; + +static const AVRational default_tb = { 1, 90000 }; + +/* functions for frameAlloc */ +static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, + mfxFrameAllocResponse *resp) +{ + QSVVPPContext *s = pthis; + int i; + + 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 (req->Type & MFX_MEMTYPE_FROM_VPPIN) { + resp->mids = av_mallocz(s->nb_surface_ptrs_in * sizeof(*resp->mids)); + if (!resp->mids) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_surface_ptrs_in; i++) + resp->mids[i] = s->surface_ptrs_in[i]->Data.MemId; + + resp->NumFrameActual = s->nb_surface_ptrs_in; + } else { + resp->mids = av_mallocz(s->nb_surface_ptrs_out * sizeof(*resp->mids)); + if (!resp->mids) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_surface_ptrs_out; i++) + resp->mids[i] = s->surface_ptrs_out[i]->Data.MemId; + + resp->NumFrameActual = s->nb_surface_ptrs_out; + } + + return MFX_ERR_NONE; +} + +static mfxStatus frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) +{ + av_freep(&resp->mids); + 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 pix_fmt_to_mfx_fourcc(int format) +{ + switch (format) { + case AV_PIX_FMT_YUV420P: + return MFX_FOURCC_YV12; + case AV_PIX_FMT_NV12: + return MFX_FOURCC_NV12; + case AV_PIX_FMT_YUYV422: + return MFX_FOURCC_YUY2; + case AV_PIX_FMT_RGB32: + return MFX_FOURCC_RGB4; + } + + return MFX_FOURCC_NV12; +} + +static int map_frame_to_surface(AVFrame *frame, mfxFrameSurface1 *surface) +{ + switch (frame->format) { + case AV_PIX_FMT_NV12: + 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_YUYV422: + surface->Data.Y = frame->data[0]; + surface->Data.U = frame->data[0] + 1; + surface->Data.V = frame->data[0] + 3; + break; + case AV_PIX_FMT_RGB32: + 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]; + + return 0; +} + +/* fill the surface info */ +static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link) +{ + enum AVPixelFormat pix_fmt; + AVHWFramesContext *frames_ctx; + AVQSVFramesContext *frames_hwctx; + const AVPixFmtDescriptor *desc; + + if (link->format == AV_PIX_FMT_QSV) { + if (!link->hw_frames_ctx) + return AVERROR(EINVAL); + + frames_ctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + frames_hwctx = frames_ctx->hwctx; + *frameinfo = frames_hwctx->surfaces[0].Info; + } else { + pix_fmt = link->format; + desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return AVERROR_BUG; + + frameinfo->CropX = 0; + frameinfo->CropY = 0; + frameinfo->Width = FFALIGN(link->w, 32); + frameinfo->Height = FFALIGN(link->h, 32); + frameinfo->PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + frameinfo->FourCC = pix_fmt_to_mfx_fourcc(pix_fmt); + frameinfo->BitDepthLuma = desc->comp[0].depth; + frameinfo->BitDepthChroma = desc->comp[0].depth; + frameinfo->Shift = desc->comp[0].depth > 8; + if (desc->log2_chroma_w && desc->log2_chroma_h) + frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV420; + else if (desc->log2_chroma_w) + frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV422; + else + frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV444; + } + + frameinfo->CropW = link->w; + frameinfo->CropH = link->h; + frameinfo->FrameRateExtN = link->frame_rate.num; + frameinfo->FrameRateExtD = link->frame_rate.den; + frameinfo->AspectRatioW = link->sample_aspect_ratio.num ? link->sample_aspect_ratio.num : 1; + frameinfo->AspectRatioH = link->sample_aspect_ratio.den ? link->sample_aspect_ratio.den : 1; + + return 0; +} + +static void clear_unused_frames(QSVFrame *list) +{ + while (list) { + if (list->surface && !list->surface->Data.Locked) { + list->surface = NULL; + av_frame_free(&list->frame); + } + list = list->next; + } +} + +static void clear_frame_list(QSVFrame **list) +{ + while (*list) { + QSVFrame *frame; + + frame = *list; + *list = (*list)->next; + av_frame_free(&frame->frame); + av_freep(&frame); + } +} + +static QSVFrame *get_free_frame(QSVFrame **list) +{ + QSVFrame *out = *list; + + for (; out; out = out->next) { + if (!out->surface) + break; + } + + if (!out) { + out = av_mallocz(sizeof(*out)); + if (!out) { + av_log(NULL, AV_LOG_ERROR, "Can't alloc new output frame.\n"); + return NULL; + } + out->next = *list; + *list = out; + } + + return out; +} + +/* get the input surface */ +static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref) +{ + QSVFrame *qsv_frame; + AVFilterContext *ctx = inlink->dst; + + clear_unused_frames(s->in_frame_list); + + qsv_frame = get_free_frame(&s->in_frame_list); + if (!qsv_frame) + return NULL; + + /* Turn AVFrame into mfxFrameSurface1. + * For video/opaque memory mode, pix_fmt is AV_PIX_FMT_QSV, and + * mfxFrameSurface1 is stored in AVFrame->data[3]; + * for system memory mode, raw video data is stored in + * AVFrame, we should map it into mfxFrameSurface1. + */ + if (!IS_SYSTEM_MEMORY(s->in_mem_mode)) { + if (picref->format != AV_PIX_FMT_QSV) { + av_log(ctx, AV_LOG_ERROR, "QSVVPP gets a wrong frame.\n"); + return NULL; + } + qsv_frame->frame = picref; + qsv_frame->surface = (mfxFrameSurface1 *)qsv_frame->frame->data[3]; + } else { + /* make a copy if the input is not padded as libmfx requires */ + if (picref->height & 31 || picref->linesize[0] & 31) { + qsv_frame->frame = ff_get_video_buffer(inlink, + FFALIGN(inlink->w, 32), + FFALIGN(inlink->h, 32)); + if (!qsv_frame->frame) + return NULL; + + qsv_frame->frame->width = picref->width; + qsv_frame->frame->height = picref->height; + + if (av_frame_copy(qsv_frame->frame, picref) < 0) { + av_frame_free(&qsv_frame->frame); + return NULL; + } + + av_frame_copy_props(qsv_frame->frame, picref); + av_frame_free(&picref); + } else + qsv_frame->frame = picref; + + if (map_frame_to_surface(qsv_frame->frame, + &qsv_frame->surface_internal) < 0) { + av_log(ctx, AV_LOG_ERROR, "Unsupported frame.\n"); + return NULL; + } + qsv_frame->surface = &qsv_frame->surface_internal; + } + + qsv_frame->surface->Info = s->frame_infos[FF_INLINK_IDX(inlink)]; + qsv_frame->surface->Data.TimeStamp = av_rescale_q(qsv_frame->frame->pts, + inlink->time_base, default_tb); + + qsv_frame->surface->Info.PicStruct = + !qsv_frame->frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE : + (qsv_frame->frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF : + MFX_PICSTRUCT_FIELD_BFF); + if (qsv_frame->frame->repeat_pict == 1) + qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED; + else if (qsv_frame->frame->repeat_pict == 2) + qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING; + else if (qsv_frame->frame->repeat_pict == 4) + qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING; + + return qsv_frame; +} + +/* get the output surface */ +static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + QSVFrame *out_frame; + int ret; + + clear_unused_frames(s->out_frame_list); + + out_frame = get_free_frame(&s->out_frame_list); + if (!out_frame) + return NULL; + + /* For video memory, get a hw frame; + * For system memory, get a sw frame and map it into a mfx_surface. */ + if (!IS_SYSTEM_MEMORY(s->out_mem_mode)) { + out_frame->frame = av_frame_alloc(); + if (!out_frame->frame) + return NULL; + + ret = av_hwframe_get_buffer(outlink->hw_frames_ctx, out_frame->frame, 0); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Can't allocate a surface.\n"); + return NULL; + } + + out_frame->surface = (mfxFrameSurface1 *)out_frame->frame->data[3]; + } else { + /* Get a frame with aligned dimensions. + * Libmfx need system memory being 128x64 aligned */ + out_frame->frame = ff_get_video_buffer(outlink, + FFALIGN(outlink->w, 128), + FFALIGN(outlink->h, 64)); + if (!out_frame->frame) + return NULL; + + out_frame->frame->width = outlink->w; + out_frame->frame->height = outlink->h; + + ret = map_frame_to_surface(out_frame->frame, + &out_frame->surface_internal); + if (ret < 0) + return NULL; + + out_frame->surface = &out_frame->surface_internal; + } + + out_frame->surface->Info = s->vpp_param.vpp.Out; + + return out_frame; +} + +/* create the QSV session */ +static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) +{ + AVFilterLink *inlink = avctx->inputs[0]; + AVFilterLink *outlink = avctx->outputs[0]; + AVQSVFramesContext *in_frames_hwctx = NULL; + AVQSVFramesContext *out_frames_hwctx = NULL; + + AVBufferRef *device_ref; + AVHWDeviceContext *device_ctx; + AVQSVDeviceContext *device_hwctx; + mfxHDL handle; + mfxHandleType handle_type; + mfxVersion ver; + mfxIMPL impl; + int ret, i; + + if (inlink->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + + device_ref = frames_ctx->device_ref; + in_frames_hwctx = frames_ctx->hwctx; + + s->in_mem_mode = in_frames_hwctx->frame_type; + + s->surface_ptrs_in = av_mallocz_array(in_frames_hwctx->nb_surfaces, + sizeof(*s->surface_ptrs_in)); + if (!s->surface_ptrs_in) + return AVERROR(ENOMEM); + + for (i = 0; i < in_frames_hwctx->nb_surfaces; i++) + s->surface_ptrs_in[i] = in_frames_hwctx->surfaces + i; + + s->nb_surface_ptrs_in = in_frames_hwctx->nb_surfaces; + } else if (avctx->hw_device_ctx) { + device_ref = avctx->hw_device_ctx; + s->in_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; + } else { + av_log(avctx, AV_LOG_ERROR, "No hw context provided.\n"); + return AVERROR(EINVAL); + } + + device_ctx = (AVHWDeviceContext *)device_ref->data; + device_hwctx = device_ctx->hwctx; + + if (outlink->format == AV_PIX_FMT_QSV) { + AVHWFramesContext *out_frames_ctx; + AVBufferRef *out_frames_ref = av_hwframe_ctx_alloc(device_ref); + if (!out_frames_ref) + return AVERROR(ENOMEM); + + s->out_mem_mode = IS_OPAQUE_MEMORY(s->in_mem_mode) ? + MFX_MEMTYPE_OPAQUE_FRAME : + MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + + out_frames_ctx = (AVHWFramesContext *)out_frames_ref->data; + out_frames_hwctx = out_frames_ctx->hwctx; + + out_frames_ctx->format = AV_PIX_FMT_QSV; + out_frames_ctx->width = FFALIGN(outlink->w, 32); + out_frames_ctx->height = FFALIGN(outlink->h, 32); + out_frames_ctx->sw_format = s->out_sw_format; + out_frames_ctx->initial_pool_size = 64; + out_frames_hwctx->frame_type = s->out_mem_mode; + + ret = av_hwframe_ctx_init(out_frames_ref); + if (ret < 0) { + av_buffer_unref(&out_frames_ref); + av_log(avctx, AV_LOG_ERROR, "Error creating frames_ctx for output pad.\n"); + return ret; + } + + s->surface_ptrs_out = av_mallocz_array(out_frames_hwctx->nb_surfaces, + sizeof(*s->surface_ptrs_out)); + if (!s->surface_ptrs_out) { + av_buffer_unref(&out_frames_ref); + return AVERROR(ENOMEM); + } + + for (i = 0; i < out_frames_hwctx->nb_surfaces; i++) + s->surface_ptrs_out[i] = out_frames_hwctx->surfaces + i; + s->nb_surface_ptrs_out = out_frames_hwctx->nb_surfaces; + + av_buffer_unref(&outlink->hw_frames_ctx); + outlink->hw_frames_ctx = out_frames_ref; + } else + s->out_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; + + /* extract the properties of the "master" session given to us */ + ret = MFXQueryIMPL(device_hwctx->session, &impl); + if (ret == MFX_ERR_NONE) + ret = MFXQueryVersion(device_hwctx->session, &ver); + if (ret != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n"); + return AVERROR_UNKNOWN; + } + + for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { + ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle); + if (ret == MFX_ERR_NONE) { + handle_type = handle_types[i]; + break; + } + } + + /* create a "slave" session with those same properties, to be used for vpp */ + ret = MFXInit(impl, &ver, &s->session); + if (ret != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error initializing a session for scaling\n"); + return AVERROR_UNKNOWN; + } + + if (handle) { + ret = MFXVideoCORE_SetHandle(s->session, handle_type, handle); + if (ret != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + ret = MFXJoinSession(device_hwctx->session, s->session); + if (ret != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + + if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) { + s->opaque_alloc.In.Surfaces = s->surface_ptrs_in; + s->opaque_alloc.In.NumSurface = s->nb_surface_ptrs_in; + s->opaque_alloc.In.Type = s->in_mem_mode; + + s->opaque_alloc.Out.Surfaces = s->surface_ptrs_out; + s->opaque_alloc.Out.NumSurface = s->nb_surface_ptrs_out; + s->opaque_alloc.Out.Type = s->out_mem_mode; + + s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); + } else if (IS_VIDEO_MEMORY(s->in_mem_mode) || IS_VIDEO_MEMORY(s->out_mem_mode)) { + mfxFrameAllocator frame_allocator = { + .pthis = s, + .Alloc = frame_alloc, + .Lock = frame_lock, + .Unlock = frame_unlock, + .GetHDL = frame_get_hdl, + .Free = frame_free, + }; + + ret = MFXVideoCORE_SetFrameAllocator(s->session, &frame_allocator); + if (ret != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + + return 0; +} + +int ff_qsvvpp_create(AVFilterContext *avctx, QSVVPPContext **vpp, QSVVPPParam *param) +{ + int i; + int ret; + QSVVPPContext *s; + + s = av_mallocz(sizeof(*s)); + if (!s) + return AVERROR(ENOMEM); + + s->filter_frame = param->filter_frame; + if (!s->filter_frame) + s->filter_frame = ff_filter_frame; + s->out_sw_format = param->out_sw_format; + + /* create the vpp session */ + ret = init_vpp_session(avctx, s); + if (ret < 0) + goto failed; + + s->frame_infos = av_mallocz_array(avctx->nb_inputs, sizeof(*s->frame_infos)); + if (!s->frame_infos) { + ret = AVERROR(ENOMEM); + goto failed; + } + + /* Init each input's information */ + for (i = 0; i < avctx->nb_inputs; i++) { + ret = fill_frameinfo_by_link(&s->frame_infos[i], avctx->inputs[i]); + if (ret < 0) + goto failed; + } + + /* Update input's frame info according to crop */ + for (i = 0; i < param->num_crop; i++) { + QSVVPPCrop *crop = param->crop + i; + if (crop->in_idx > avctx->nb_inputs) { + ret = AVERROR(EINVAL); + goto failed; + } + s->frame_infos[crop->in_idx].CropX = crop->x; + s->frame_infos[crop->in_idx].CropY = crop->y; + s->frame_infos[crop->in_idx].CropW = crop->w; + s->frame_infos[crop->in_idx].CropH = crop->h; + } + + s->vpp_param.vpp.In = s->frame_infos[0]; + + ret = fill_frameinfo_by_link(&s->vpp_param.vpp.Out, avctx->outputs[0]); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Fail to get frame info from link.\n"); + goto failed; + } + + if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) { + s->nb_ext_buffers = param->num_ext_buf + 1; + s->ext_buffers = av_mallocz_array(s->nb_ext_buffers, sizeof(*s->ext_buffers)); + if (!s->ext_buffers) { + ret = AVERROR(ENOMEM); + goto failed; + } + + s->ext_buffers[0] = (mfxExtBuffer *)&s->opaque_alloc; + for (i = 1; i < param->num_ext_buf; i++) + s->ext_buffers[i] = param->ext_buf[i - 1]; + s->vpp_param.ExtParam = s->ext_buffers; + s->vpp_param.NumExtParam = s->nb_ext_buffers; + } else { + s->vpp_param.NumExtParam = param->num_ext_buf; + s->vpp_param.ExtParam = param->ext_buf; + } + + s->vpp_param.AsyncDepth = 1; + + if (IS_SYSTEM_MEMORY(s->in_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_SYSTEM_MEMORY; + else if (IS_VIDEO_MEMORY(s->in_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_VIDEO_MEMORY; + else if (IS_OPAQUE_MEMORY(s->in_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_OPAQUE_MEMORY; + + if (IS_SYSTEM_MEMORY(s->out_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + else if (IS_VIDEO_MEMORY(s->out_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_VIDEO_MEMORY; + else if (IS_OPAQUE_MEMORY(s->out_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + + ret = MFXVideoVPP_Init(s->session, &s->vpp_param); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to create a qsvvpp, ret = %d.\n", ret); + goto failed; + } + + *vpp = s; + return 0; + +failed: + ff_qsvvpp_free(&s); + + return ret; +} + +int ff_qsvvpp_free(QSVVPPContext **vpp) +{ + QSVVPPContext *s = *vpp; + + if (!s) + return 0; + + if (s->session) { + MFXVideoVPP_Close(s->session); + MFXClose(s->session); + } + + /* release all the resources */ + clear_frame_list(&s->in_frame_list); + clear_frame_list(&s->out_frame_list); + av_freep(&s->surface_ptrs_in); + av_freep(&s->surface_ptrs_out); + av_freep(&s->ext_buffers); + av_freep(&s->frame_infos); + av_freep(vpp); + + return 0; +} + +int ff_qsvvpp_filter_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + mfxSyncPoint sync; + QSVFrame *in_frame, *out_frame; + int ret, filter_ret; + + in_frame = submit_frame(s, inlink, picref); + if (!in_frame) { + av_log(ctx, AV_LOG_ERROR, "Failed to submit frame on input[%d]\n", + FF_INLINK_IDX(inlink)); + return AVERROR(ENOMEM); + } + + do { + out_frame = query_frame(s, outlink); + if (!out_frame) { + av_log(ctx, AV_LOG_ERROR, "Failed to query an output frame.\n"); + return AVERROR(ENOMEM); + } + + do { + ret = MFXVideoVPP_RunFrameVPPAsync(s->session, in_frame->surface, + out_frame->surface, NULL, &sync); + if (ret == MFX_WRN_DEVICE_BUSY) + av_usleep(500); + } while (ret == MFX_WRN_DEVICE_BUSY); + + if (ret < 0 && ret != MFX_ERR_MORE_SURFACE) { + /* Ignore more_data error */ + if (ret == MFX_ERR_MORE_DATA) + ret = AVERROR(EAGAIN); + break; + } + + if (MFXVideoCORE_SyncOperation(s->session, sync, 1000) < 0) + av_log(ctx, AV_LOG_WARNING, "Sync failed.\n"); + + out_frame->frame->pts = av_rescale_q(out_frame->surface->Data.TimeStamp, + default_tb, outlink->time_base); + + filter_ret = s->filter_frame(outlink, out_frame->frame); + if (filter_ret < 0) { + av_frame_free(&out_frame->frame); + ret = filter_ret; + break; + } + out_frame->frame = NULL; + } while(ret == MFX_ERR_MORE_SURFACE); + + return ret; +} diff --git a/libavfilter/qsvvpp.h b/libavfilter/qsvvpp.h new file mode 100644 index 000000000..d720c9ba4 --- /dev/null +++ b/libavfilter/qsvvpp.h @@ -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 + */ + +/** + * @file + * Intel Quick Sync Video VPP base function + */ + +#ifndef AVFILTER_QSVVPP_H +#define AVFILTER_QSVVPP_H + +#include + +#include "avfilter.h" + +#define FF_INLINK_IDX(link) ((int)((link)->dstpad - (link)->dst->input_pads)) +#define FF_OUTLINK_IDX(link) ((int)((link)->srcpad - (link)->src->output_pads)) + +typedef struct QSVVPPContext QSVVPPContext; + +typedef struct QSVVPPCrop { + int in_idx; ///< Input index + int x, y, w, h; ///< Crop rectangle +} QSVVPPCrop; + +typedef struct QSVVPPParam { + /* default is ff_filter_frame */ + int (*filter_frame)(AVFilterLink *outlink, AVFrame *frame); + + /* To fill with MFX enhanced filter configurations */ + int num_ext_buf; + mfxExtBuffer **ext_buf; + + /* Real output format */ + enum AVPixelFormat out_sw_format; + + /* Crop information for each input, if needed */ + int num_crop; + QSVVPPCrop *crop; +} QSVVPPParam; + +/* create and initialize the QSV session */ +int ff_qsvvpp_create(AVFilterContext *avctx, QSVVPPContext **vpp, QSVVPPParam *param); + +/* release the resources (eg.surfaces) */ +int ff_qsvvpp_free(QSVVPPContext **vpp); + +/* vpp filter frame and call the cb if needed */ +int ff_qsvvpp_filter_frame(QSVVPPContext *vpp, AVFilterLink *inlink, AVFrame *frame); + +#endif /* AVFILTER_QSVVPP_H */ diff --git a/libavfilter/tests/.gitignore b/libavfilter/tests/.gitignore new file mode 100644 index 000000000..65ef86f2e --- /dev/null +++ b/libavfilter/tests/.gitignore @@ -0,0 +1,4 @@ +/drawutils +/filtfmts +/formats +/integral diff --git a/libavfilter/tests/filtfmts.c b/libavfilter/tests/filtfmts.c index 199d74d7a..72b860ae5 100644 --- a/libavfilter/tests/filtfmts.c +++ b/libavfilter/tests/filtfmts.c @@ -73,7 +73,7 @@ static void print_formats(AVFilterContext *filter_ctx) int main(int argc, char **argv) { - AVFilter *filter; + const AVFilter *filter; AVFilterContext *filter_ctx; AVFilterGraph *graph_ctx; const char *filter_name; diff --git a/libavfilter/threshold.h b/libavfilter/threshold.h new file mode 100644 index 000000000..775a9f9ca --- /dev/null +++ b/libavfilter/threshold.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 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_THRESHOLD_H +#define AVFILTER_THRESHOLD_H + +#include "avfilter.h" +#include "framesync.h" + +typedef struct ThresholdContext { + const AVClass *class; + + int depth; + int planes; + int bpc; + + int nb_planes; + int width[4], height[4]; + + void (*threshold)(const uint8_t *in, const uint8_t *threshold, + const uint8_t *min, const uint8_t *max, + uint8_t *out, + ptrdiff_t ilinesize, ptrdiff_t tlinesize, + ptrdiff_t flinesize, ptrdiff_t slinesize, + ptrdiff_t olinesize, + int w, int h); + + AVFrame *frames[4]; + FFFrameSync fs; +} ThresholdContext; + +void ff_threshold_init(ThresholdContext *s); +void ff_threshold_init_x86(ThresholdContext *s); + +#endif /* AVFILTER_THRESHOLD_H */ diff --git a/libavfilter/unsharp.h b/libavfilter/unsharp.h index 340a6a0ca..caff986fc 100644 --- a/libavfilter/unsharp.h +++ b/libavfilter/unsharp.h @@ -24,38 +24,10 @@ #include "config.h" #include "avfilter.h" -#if CONFIG_OPENCL -#include "libavutil/opencl.h" -#endif #define MIN_MATRIX_SIZE 3 #define MAX_MATRIX_SIZE 63 -#if CONFIG_OPENCL - -typedef struct UnsharpOpenclContext { - cl_command_queue command_queue; - cl_program program; - cl_kernel kernel_default; - cl_kernel kernel_luma; - cl_kernel kernel_chroma; - cl_mem cl_luma_mask; - cl_mem cl_chroma_mask; - cl_mem cl_luma_mask_x; - cl_mem cl_chroma_mask_x; - cl_mem cl_luma_mask_y; - cl_mem cl_chroma_mask_y; - int in_plane_size[8]; - int out_plane_size[8]; - int plane_num; - cl_mem cl_inbuf; - size_t cl_inbuf_size; - cl_mem cl_outbuf; - size_t cl_outbuf_size; - int use_fast_kernels; -} UnsharpOpenclContext; - -#endif typedef struct UnsharpFilterParam { int msize_x; ///< matrix width @@ -76,9 +48,6 @@ typedef struct UnsharpContext { UnsharpFilterParam chroma; ///< chroma parameters (width, height, amount) int hsub, vsub; int opencl; -#if CONFIG_OPENCL - UnsharpOpenclContext opencl_ctx; -#endif int (* apply_unsharp)(AVFilterContext *ctx, AVFrame *in, AVFrame *out); } UnsharpContext; diff --git a/libavfilter/unsharp_opencl.c b/libavfilter/unsharp_opencl.c deleted file mode 100644 index 154545584..000000000 --- a/libavfilter/unsharp_opencl.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - * unsharp input video - */ - -#include "unsharp_opencl.h" -#include "libavutil/common.h" -#include "libavutil/opencl_internal.h" - -#define PLANE_NUM 3 -#define ROUND_TO_16(a) (((((a) - 1)/16)+1)*16) - -static inline void add_mask_counter(uint32_t *dst, uint32_t *counter1, uint32_t *counter2, int len) -{ - int i; - for (i = 0; i < len; i++) { - dst[i] = counter1[i] + counter2[i]; - } -} - -static int compute_mask(int step, uint32_t *mask) -{ - int i, z, ret = 0; - int counter_size = sizeof(uint32_t) * (2 * step + 1); - uint32_t *temp1_counter, *temp2_counter, **counter = NULL; - temp1_counter = av_mallocz(counter_size); - if (!temp1_counter) { - ret = AVERROR(ENOMEM); - goto end; - } - temp2_counter = av_mallocz(counter_size); - if (!temp2_counter) { - ret = AVERROR(ENOMEM); - goto end; - } - counter = av_mallocz_array(2 * step + 1, sizeof(uint32_t *)); - if (!counter) { - ret = AVERROR(ENOMEM); - goto end; - } - for (i = 0; i < 2 * step + 1; i++) { - counter[i] = av_mallocz(counter_size); - if (!counter[i]) { - ret = AVERROR(ENOMEM); - goto end; - } - } - for (i = 0; i < 2 * step + 1; i++) { - memset(temp1_counter, 0, counter_size); - temp1_counter[i] = 1; - for (z = 0; z < step * 2; z += 2) { - add_mask_counter(temp2_counter, counter[z], temp1_counter, step * 2); - memcpy(counter[z], temp1_counter, counter_size); - add_mask_counter(temp1_counter, counter[z + 1], temp2_counter, step * 2); - memcpy(counter[z + 1], temp2_counter, counter_size); - } - } - memcpy(mask, temp1_counter, counter_size); -end: - av_freep(&temp1_counter); - av_freep(&temp2_counter); - for (i = 0; counter && i < 2 * step + 1; i++) { - av_freep(&counter[i]); - } - av_freep(&counter); - return ret; -} - -static int copy_separable_masks(cl_mem cl_mask_x, cl_mem cl_mask_y, int step_x, int step_y) -{ - int ret = 0; - uint32_t *mask_x, *mask_y; - size_t size_mask_x = sizeof(uint32_t) * (2 * step_x + 1); - size_t size_mask_y = sizeof(uint32_t) * (2 * step_y + 1); - mask_x = av_mallocz_array(2 * step_x + 1, sizeof(uint32_t)); - if (!mask_x) { - ret = AVERROR(ENOMEM); - goto end; - } - mask_y = av_mallocz_array(2 * step_y + 1, sizeof(uint32_t)); - if (!mask_y) { - ret = AVERROR(ENOMEM); - goto end; - } - - ret = compute_mask(step_x, mask_x); - if (ret < 0) - goto end; - ret = compute_mask(step_y, mask_y); - if (ret < 0) - goto end; - - ret = av_opencl_buffer_write(cl_mask_x, (uint8_t *)mask_x, size_mask_x); - ret = av_opencl_buffer_write(cl_mask_y, (uint8_t *)mask_y, size_mask_y); -end: - av_freep(&mask_x); - av_freep(&mask_y); - - return ret; -} - -static int generate_mask(AVFilterContext *ctx) -{ - cl_mem masks[4]; - cl_mem mask_matrix[2]; - int i, ret = 0, step_x[2], step_y[2]; - - UnsharpContext *unsharp = ctx->priv; - mask_matrix[0] = unsharp->opencl_ctx.cl_luma_mask; - mask_matrix[1] = unsharp->opencl_ctx.cl_chroma_mask; - masks[0] = unsharp->opencl_ctx.cl_luma_mask_x; - masks[1] = unsharp->opencl_ctx.cl_luma_mask_y; - masks[2] = unsharp->opencl_ctx.cl_chroma_mask_x; - masks[3] = unsharp->opencl_ctx.cl_chroma_mask_y; - step_x[0] = unsharp->luma.steps_x; - step_x[1] = unsharp->chroma.steps_x; - step_y[0] = unsharp->luma.steps_y; - step_y[1] = unsharp->chroma.steps_y; - - /* use default kernel if any matrix dim larger than 8 due to limited local mem size */ - if (step_x[0]>8 || step_x[1]>8 || step_y[0]>8 || step_y[1]>8) - unsharp->opencl_ctx.use_fast_kernels = 0; - else - unsharp->opencl_ctx.use_fast_kernels = 1; - - if (!masks[0] || !masks[1] || !masks[2] || !masks[3]) { - av_log(ctx, AV_LOG_ERROR, "Luma mask and chroma mask should not be NULL\n"); - return AVERROR(EINVAL); - } - if (!mask_matrix[0] || !mask_matrix[1]) { - av_log(ctx, AV_LOG_ERROR, "Luma mask and chroma mask should not be NULL\n"); - return AVERROR(EINVAL); - } - for (i = 0; i < 2; i++) { - ret = copy_separable_masks(masks[2*i], masks[2*i+1], step_x[i], step_y[i]); - if (ret < 0) - return ret; - } - return ret; -} - -int ff_opencl_apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out) -{ - int ret; - AVFilterLink *link = ctx->inputs[0]; - UnsharpContext *unsharp = ctx->priv; - cl_int status; - FFOpenclParam kernel1 = {0}; - FFOpenclParam kernel2 = {0}; - int width = link->w; - int height = link->h; - int cw = AV_CEIL_RSHIFT(link->w, unsharp->hsub); - int ch = AV_CEIL_RSHIFT(link->h, unsharp->vsub); - size_t globalWorkSize1d = width * height + 2 * ch * cw; - size_t globalWorkSize2dLuma[2]; - size_t globalWorkSize2dChroma[2]; - size_t localWorkSize2d[2] = {16, 16}; - - if (unsharp->opencl_ctx.use_fast_kernels) { - globalWorkSize2dLuma[0] = (size_t)ROUND_TO_16(width); - globalWorkSize2dLuma[1] = (size_t)ROUND_TO_16(height); - globalWorkSize2dChroma[0] = (size_t)ROUND_TO_16(cw); - globalWorkSize2dChroma[1] = (size_t)(2*ROUND_TO_16(ch)); - - kernel1.ctx = ctx; - kernel1.kernel = unsharp->opencl_ctx.kernel_luma; - ret = avpriv_opencl_set_parameter(&kernel1, - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask_x), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask_y), - FF_OPENCL_PARAM_INFO(unsharp->luma.amount), - FF_OPENCL_PARAM_INFO(unsharp->luma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->luma.halfscale), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(width), - FF_OPENCL_PARAM_INFO(height), - NULL); - if (ret < 0) - return ret; - - kernel2.ctx = ctx; - kernel2.kernel = unsharp->opencl_ctx.kernel_chroma; - ret = avpriv_opencl_set_parameter(&kernel2, - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask_x), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask_y), - FF_OPENCL_PARAM_INFO(unsharp->chroma.amount), - FF_OPENCL_PARAM_INFO(unsharp->chroma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->chroma.halfscale), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(in->linesize[1]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[1]), - FF_OPENCL_PARAM_INFO(link->w), - FF_OPENCL_PARAM_INFO(link->h), - FF_OPENCL_PARAM_INFO(cw), - FF_OPENCL_PARAM_INFO(ch), - NULL); - if (ret < 0) - return ret; - status = clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue, - unsharp->opencl_ctx.kernel_luma, 2, NULL, - globalWorkSize2dLuma, localWorkSize2d, 0, NULL, NULL); - status |=clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue, - unsharp->opencl_ctx.kernel_chroma, 2, NULL, - globalWorkSize2dChroma, localWorkSize2d, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - } else { /* use default kernel */ - kernel1.ctx = ctx; - kernel1.kernel = unsharp->opencl_ctx.kernel_default; - - ret = avpriv_opencl_set_parameter(&kernel1, - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask), - FF_OPENCL_PARAM_INFO(unsharp->luma.amount), - FF_OPENCL_PARAM_INFO(unsharp->chroma.amount), - FF_OPENCL_PARAM_INFO(unsharp->luma.steps_x), - FF_OPENCL_PARAM_INFO(unsharp->luma.steps_y), - FF_OPENCL_PARAM_INFO(unsharp->chroma.steps_x), - FF_OPENCL_PARAM_INFO(unsharp->chroma.steps_y), - FF_OPENCL_PARAM_INFO(unsharp->luma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->chroma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->luma.halfscale), - FF_OPENCL_PARAM_INFO(unsharp->chroma.halfscale), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(in->linesize[1]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[1]), - FF_OPENCL_PARAM_INFO(link->h), - FF_OPENCL_PARAM_INFO(link->w), - FF_OPENCL_PARAM_INFO(ch), - FF_OPENCL_PARAM_INFO(cw), - NULL); - if (ret < 0) - return ret; - status = clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue, - unsharp->opencl_ctx.kernel_default, 1, NULL, - &globalWorkSize1d, NULL, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - } - //blocking map is suffficient, no need for clFinish - //clFinish(unsharp->opencl_ctx.command_queue); - - return av_opencl_buffer_read_image(out->data, unsharp->opencl_ctx.out_plane_size, - unsharp->opencl_ctx.plane_num, unsharp->opencl_ctx.cl_outbuf, - unsharp->opencl_ctx.cl_outbuf_size); -} - -int ff_opencl_unsharp_init(AVFilterContext *ctx) -{ - int ret = 0; - char build_opts[96]; - UnsharpContext *unsharp = ctx->priv; - ret = av_opencl_init(NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask, - sizeof(uint32_t) * (2 * unsharp->luma.steps_x + 1) * (2 * unsharp->luma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask, - sizeof(uint32_t) * (2 * unsharp->chroma.steps_x + 1) * (2 * unsharp->chroma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - // separable filters - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask_x, - sizeof(uint32_t) * (2 * unsharp->luma.steps_x + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask_y, - sizeof(uint32_t) * (2 * unsharp->luma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask_x, - sizeof(uint32_t) * (2 * unsharp->chroma.steps_x + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask_y, - sizeof(uint32_t) * (2 * unsharp->chroma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = generate_mask(ctx); - if (ret < 0) - return ret; - unsharp->opencl_ctx.plane_num = PLANE_NUM; - unsharp->opencl_ctx.command_queue = av_opencl_get_command_queue(); - if (!unsharp->opencl_ctx.command_queue) { - av_log(ctx, AV_LOG_ERROR, "Unable to get OpenCL command queue in filter 'unsharp'\n"); - return AVERROR(EINVAL); - } - snprintf(build_opts, 96, "-D LU_RADIUS_X=%d -D LU_RADIUS_Y=%d -D CH_RADIUS_X=%d -D CH_RADIUS_Y=%d", - 2*unsharp->luma.steps_x+1, 2*unsharp->luma.steps_y+1, 2*unsharp->chroma.steps_x+1, 2*unsharp->chroma.steps_y+1); - unsharp->opencl_ctx.program = av_opencl_compile("unsharp", build_opts); - if (!unsharp->opencl_ctx.program) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to compile program 'unsharp'\n"); - return AVERROR(EINVAL); - } - if (unsharp->opencl_ctx.use_fast_kernels) { - if (!unsharp->opencl_ctx.kernel_luma) { - unsharp->opencl_ctx.kernel_luma = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_luma", &ret); - if (ret != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_luma'\n"); - return ret; - } - } - if (!unsharp->opencl_ctx.kernel_chroma) { - unsharp->opencl_ctx.kernel_chroma = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_chroma", &ret); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_chroma'\n"); - return ret; - } - } - } - else { - if (!unsharp->opencl_ctx.kernel_default) { - unsharp->opencl_ctx.kernel_default = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_default", &ret); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_default'\n"); - return ret; - } - } - } - return ret; -} - -void ff_opencl_unsharp_uninit(AVFilterContext *ctx) -{ - UnsharpContext *unsharp = ctx->priv; - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_inbuf); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_outbuf); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask_x); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask_x); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask_y); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask_y); - clReleaseKernel(unsharp->opencl_ctx.kernel_default); - clReleaseKernel(unsharp->opencl_ctx.kernel_luma); - clReleaseKernel(unsharp->opencl_ctx.kernel_chroma); - clReleaseProgram(unsharp->opencl_ctx.program); - unsharp->opencl_ctx.command_queue = NULL; - av_opencl_uninit(); -} - -int ff_opencl_unsharp_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out) -{ - int ret = 0; - AVFilterLink *link = ctx->inputs[0]; - UnsharpContext *unsharp = ctx->priv; - int ch = AV_CEIL_RSHIFT(link->h, unsharp->vsub); - - if ((!unsharp->opencl_ctx.cl_inbuf) || (!unsharp->opencl_ctx.cl_outbuf)) { - unsharp->opencl_ctx.in_plane_size[0] = (in->linesize[0] * in->height); - unsharp->opencl_ctx.in_plane_size[1] = (in->linesize[1] * ch); - unsharp->opencl_ctx.in_plane_size[2] = (in->linesize[2] * ch); - unsharp->opencl_ctx.out_plane_size[0] = (out->linesize[0] * out->height); - unsharp->opencl_ctx.out_plane_size[1] = (out->linesize[1] * ch); - unsharp->opencl_ctx.out_plane_size[2] = (out->linesize[2] * ch); - unsharp->opencl_ctx.cl_inbuf_size = unsharp->opencl_ctx.in_plane_size[0] + - unsharp->opencl_ctx.in_plane_size[1] + - unsharp->opencl_ctx.in_plane_size[2]; - unsharp->opencl_ctx.cl_outbuf_size = unsharp->opencl_ctx.out_plane_size[0] + - unsharp->opencl_ctx.out_plane_size[1] + - unsharp->opencl_ctx.out_plane_size[2]; - if (!unsharp->opencl_ctx.cl_inbuf) { - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_inbuf, - unsharp->opencl_ctx.cl_inbuf_size, - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - } - if (!unsharp->opencl_ctx.cl_outbuf) { - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_outbuf, - unsharp->opencl_ctx.cl_outbuf_size, - CL_MEM_READ_WRITE, NULL); - if (ret < 0) - return ret; - } - } - return av_opencl_buffer_write_image(unsharp->opencl_ctx.cl_inbuf, - unsharp->opencl_ctx.cl_inbuf_size, - 0, in->data, unsharp->opencl_ctx.in_plane_size, - unsharp->opencl_ctx.plane_num); -} diff --git a/libavfilter/unsharp_opencl_kernel.h b/libavfilter/unsharp_opencl_kernel.h deleted file mode 100644 index 307d0f181..000000000 --- a/libavfilter/unsharp_opencl_kernel.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_UNSHARP_OPENCL_KERNEL_H -#define AVFILTER_UNSHARP_OPENCL_KERNEL_H - -#include "libavutil/opencl.h" - -const char *ff_kernel_unsharp_opencl = AV_OPENCL_KERNEL( -inline unsigned char clip_uint8(int a) -{ - if (a & (~0xFF)) - return (-a)>>31; - else - return a; -} - -kernel void unsharp_luma( - global unsigned char *src, - global unsigned char *dst, - global int *mask_x, - global int *mask_y, - int amount, - int scalebits, - int halfscale, - int src_stride, - int dst_stride, - int width, - int height) -{ - int2 threadIdx, blockIdx, globalIdx; - threadIdx.x = get_local_id(0); - threadIdx.y = get_local_id(1); - blockIdx.x = get_group_id(0); - blockIdx.y = get_group_id(1); - globalIdx.x = get_global_id(0); - globalIdx.y = get_global_id(1); - - if (!amount) { - if (globalIdx.x < width && globalIdx.y < height) - dst[globalIdx.x + globalIdx.y*dst_stride] = src[globalIdx.x + globalIdx.y*src_stride]; - return; - } - - local unsigned int l[32][32]; - local unsigned int lcx[LU_RADIUS_X]; - local unsigned int lcy[LU_RADIUS_Y]; - int indexIx, indexIy, i, j; - - //load up tile: actual workspace + halo of 8 points in x and y \n - for(i = 0; i <= 1; i++) { - indexIy = -8 + (blockIdx.y + i) * 16 + threadIdx.y; - indexIy = indexIy < 0 ? 0 : indexIy; - indexIy = indexIy >= height ? height - 1: indexIy; - for(j = 0; j <= 1; j++) { - indexIx = -8 + (blockIdx.x + j) * 16 + threadIdx.x; - indexIx = indexIx < 0 ? 0 : indexIx; - indexIx = indexIx >= width ? width - 1: indexIx; - l[i*16 + threadIdx.y][j*16 + threadIdx.x] = src[indexIy*src_stride + indexIx]; - } - } - - int indexL = threadIdx.y*16 + threadIdx.x; - if (indexL < LU_RADIUS_X) - lcx[indexL] = mask_x[indexL]; - if (indexL < LU_RADIUS_Y) - lcy[indexL] = mask_y[indexL]; - barrier(CLK_LOCAL_MEM_FENCE); - - //needed for unsharp mask application in the end \n - int orig_value = (int)l[threadIdx.y + 8][threadIdx.x + 8]; - - int idx, idy, maskIndex; - int temp[2] = {0}; - int steps_x = (LU_RADIUS_X-1)/2; - int steps_y = (LU_RADIUS_Y-1)/2; - - // compute the actual workspace + left&right halos \n - \n#pragma unroll\n - for (j = 0; j <=1; j++) { - //extra work to cover left and right halos \n - idx = 16*j + threadIdx.x; - \n#pragma unroll\n - for (i = -steps_y; i <= steps_y; i++) { - idy = 8 + i + threadIdx.y; - maskIndex = (i + steps_y); - temp[j] += (int)l[idy][idx] * lcy[maskIndex]; - } - } - barrier(CLK_LOCAL_MEM_FENCE); - //save results from the vertical filter in local memory \n - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = 0; j <=1; j++) { - idx = 16*j + threadIdx.x; - l[idy][idx] = temp[j]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - //compute results with the horizontal filter \n - int sum = 0; - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = -steps_x; j <= steps_x; j++) { - idx = 8 + j + threadIdx.x; - maskIndex = j + steps_x; - sum += (int)l[idy][idx] * lcx[maskIndex]; - } - - int res = orig_value + (((orig_value - (int)((sum + halfscale) >> scalebits)) * amount) >> 16); - - if (globalIdx.x < width && globalIdx.y < height) - dst[globalIdx.x + globalIdx.y*dst_stride] = clip_uint8(res); -} - -kernel void unsharp_chroma( - global unsigned char *src_y, - global unsigned char *dst_y, - global int *mask_x, - global int *mask_y, - int amount, - int scalebits, - int halfscale, - int src_stride_lu, - int src_stride_ch, - int dst_stride_lu, - int dst_stride_ch, - int width, - int height, - int cw, - int ch) -{ - global unsigned char *dst_u = dst_y + height * dst_stride_lu; - global unsigned char *dst_v = dst_u + ch * dst_stride_ch; - global unsigned char *src_u = src_y + height * src_stride_lu; - global unsigned char *src_v = src_u + ch * src_stride_ch; - int2 threadIdx, blockIdx, globalIdx; - threadIdx.x = get_local_id(0); - threadIdx.y = get_local_id(1); - blockIdx.x = get_group_id(0); - blockIdx.y = get_group_id(1); - globalIdx.x = get_global_id(0); - globalIdx.y = get_global_id(1); - int padch = get_global_size(1)/2; - global unsigned char *src = globalIdx.y>=padch ? src_v : src_u; - global unsigned char *dst = globalIdx.y>=padch ? dst_v : dst_u; - - blockIdx.y = globalIdx.y>=padch ? blockIdx.y - get_num_groups(1)/2 : blockIdx.y; - globalIdx.y = globalIdx.y>=padch ? globalIdx.y - padch : globalIdx.y; - - if (!amount) { - if (globalIdx.x < cw && globalIdx.y < ch) - dst[globalIdx.x + globalIdx.y*dst_stride_ch] = src[globalIdx.x + globalIdx.y*src_stride_ch]; - return; - } - - local unsigned int l[32][32]; - local unsigned int lcx[CH_RADIUS_X]; - local unsigned int lcy[CH_RADIUS_Y]; - int indexIx, indexIy, i, j; - for(i = 0; i <= 1; i++) { - indexIy = -8 + (blockIdx.y + i) * 16 + threadIdx.y; - indexIy = indexIy < 0 ? 0 : indexIy; - indexIy = indexIy >= ch ? ch - 1: indexIy; - for(j = 0; j <= 1; j++) { - indexIx = -8 + (blockIdx.x + j) * 16 + threadIdx.x; - indexIx = indexIx < 0 ? 0 : indexIx; - indexIx = indexIx >= cw ? cw - 1: indexIx; - l[i*16 + threadIdx.y][j*16 + threadIdx.x] = src[indexIy * src_stride_ch + indexIx]; - } - } - - int indexL = threadIdx.y*16 + threadIdx.x; - if (indexL < CH_RADIUS_X) - lcx[indexL] = mask_x[indexL]; - if (indexL < CH_RADIUS_Y) - lcy[indexL] = mask_y[indexL]; - barrier(CLK_LOCAL_MEM_FENCE); - - int orig_value = (int)l[threadIdx.y + 8][threadIdx.x + 8]; - - int idx, idy, maskIndex; - int steps_x = CH_RADIUS_X/2; - int steps_y = CH_RADIUS_Y/2; - int temp[2] = {0,0}; - - \n#pragma unroll\n - for (j = 0; j <= 1; j++) { - idx = 16*j + threadIdx.x; - \n#pragma unroll\n - for (i = -steps_y; i <= steps_y; i++) { - idy = 8 + i + threadIdx.y; - maskIndex = i + steps_y; - temp[j] += (int)l[idy][idx] * lcy[maskIndex]; - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = 0; j <= 1; j++) { - idx = 16*j + threadIdx.x; - l[idy][idx] = temp[j]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - //compute results with the horizontal filter \n - int sum = 0; - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = -steps_x; j <= steps_x; j++) { - idx = 8 + j + threadIdx.x; - maskIndex = j + steps_x; - sum += (int)l[idy][idx] * lcx[maskIndex]; - } - - int res = orig_value + (((orig_value - (int)((sum + halfscale) >> scalebits)) * amount) >> 16); - - if (globalIdx.x < cw && globalIdx.y < ch) - dst[globalIdx.x + globalIdx.y*dst_stride_ch] = clip_uint8(res); -} - -kernel void unsharp_default(global unsigned char *src, - global unsigned char *dst, - const global unsigned int *mask_lu, - const global unsigned int *mask_ch, - int amount_lu, - int amount_ch, - int step_x_lu, - int step_y_lu, - int step_x_ch, - int step_y_ch, - int scalebits_lu, - int scalebits_ch, - int halfscale_lu, - int halfscale_ch, - int src_stride_lu, - int src_stride_ch, - int dst_stride_lu, - int dst_stride_ch, - int height, - int width, - int ch, - int cw) -{ - global unsigned char *dst_y = dst; - global unsigned char *dst_u = dst_y + height * dst_stride_lu; - global unsigned char *dst_v = dst_u + ch * dst_stride_ch; - - global unsigned char *src_y = src; - global unsigned char *src_u = src_y + height * src_stride_lu; - global unsigned char *src_v = src_u + ch * src_stride_ch; - - global unsigned char *temp_dst; - global unsigned char *temp_src; - const global unsigned int *temp_mask; - int global_id = get_global_id(0); - int i, j, x, y, temp_src_stride, temp_dst_stride, temp_height, temp_width, temp_steps_x, temp_steps_y, - temp_amount, temp_scalebits, temp_halfscale, sum, idx_x, idx_y, temp, res; - if (global_id < width * height) { - y = global_id / width; - x = global_id % width; - temp_dst = dst_y; - temp_src = src_y; - temp_src_stride = src_stride_lu; - temp_dst_stride = dst_stride_lu; - temp_height = height; - temp_width = width; - temp_steps_x = step_x_lu; - temp_steps_y = step_y_lu; - temp_mask = mask_lu; - temp_amount = amount_lu; - temp_scalebits = scalebits_lu; - temp_halfscale = halfscale_lu; - } else if ((global_id >= width * height) && (global_id < width * height + ch * cw)) { - y = (global_id - width * height) / cw; - x = (global_id - width * height) % cw; - temp_dst = dst_u; - temp_src = src_u; - temp_src_stride = src_stride_ch; - temp_dst_stride = dst_stride_ch; - temp_height = ch; - temp_width = cw; - temp_steps_x = step_x_ch; - temp_steps_y = step_y_ch; - temp_mask = mask_ch; - temp_amount = amount_ch; - temp_scalebits = scalebits_ch; - temp_halfscale = halfscale_ch; - } else { - y = (global_id - width * height - ch * cw) / cw; - x = (global_id - width * height - ch * cw) % cw; - temp_dst = dst_v; - temp_src = src_v; - temp_src_stride = src_stride_ch; - temp_dst_stride = dst_stride_ch; - temp_height = ch; - temp_width = cw; - temp_steps_x = step_x_ch; - temp_steps_y = step_y_ch; - temp_mask = mask_ch; - temp_amount = amount_ch; - temp_scalebits = scalebits_ch; - temp_halfscale = halfscale_ch; - } - if (temp_amount) { - sum = 0; - for (j = 0; j <= 2 * temp_steps_y; j++) { - idx_y = (y - temp_steps_y + j) <= 0 ? 0 : (y - temp_steps_y + j) >= temp_height ? temp_height-1 : y - temp_steps_y + j; - for (i = 0; i <= 2 * temp_steps_x; i++) { - idx_x = (x - temp_steps_x + i) <= 0 ? 0 : (x - temp_steps_x + i) >= temp_width ? temp_width-1 : x - temp_steps_x + i; - sum += temp_mask[i + j * (2 * temp_steps_x + 1)] * temp_src[idx_x + idx_y * temp_src_stride]; - } - } - temp = (int)temp_src[x + y * temp_src_stride]; - res = temp + (((temp - (int)((sum + temp_halfscale) >> temp_scalebits)) * temp_amount) >> 16); - temp_dst[x + y * temp_dst_stride] = clip_uint8(res); - } else { - temp_dst[x + y * temp_dst_stride] = temp_src[x + y * temp_src_stride]; - } -} -); - -#endif /* AVFILTER_UNSHARP_OPENCL_KERNEL_H */ diff --git a/libavfilter/version.h b/libavfilter/version.h index 3e67ad354..0f1172182 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -29,9 +29,9 @@ #include "libavutil/version.h" -#define LIBAVFILTER_VERSION_MAJOR 6 -#define LIBAVFILTER_VERSION_MINOR 107 -#define LIBAVFILTER_VERSION_MICRO 100 +#define LIBAVFILTER_VERSION_MAJOR 7 +#define LIBAVFILTER_VERSION_MINOR 11 +#define LIBAVFILTER_VERSION_MICRO 101 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ @@ -49,26 +49,14 @@ * the public API and may change, break or disappear at any time. */ -#ifndef FF_API_OLD_FILTER_OPTS -#define FF_API_OLD_FILTER_OPTS (LIBAVFILTER_VERSION_MAJOR < 7) -#endif #ifndef FF_API_OLD_FILTER_OPTS_ERROR -#define FF_API_OLD_FILTER_OPTS_ERROR (LIBAVFILTER_VERSION_MAJOR < 7) -#endif -#ifndef FF_API_AVFILTER_OPEN -#define FF_API_AVFILTER_OPEN (LIBAVFILTER_VERSION_MAJOR < 7) -#endif -#ifndef FF_API_AVFILTER_INIT_FILTER -#define FF_API_AVFILTER_INIT_FILTER (LIBAVFILTER_VERSION_MAJOR < 7) -#endif -#ifndef FF_API_OLD_FILTER_REGISTER -#define FF_API_OLD_FILTER_REGISTER (LIBAVFILTER_VERSION_MAJOR < 7) -#endif -#ifndef FF_API_NOCONST_GET_NAME -#define FF_API_NOCONST_GET_NAME (LIBAVFILTER_VERSION_MAJOR < 7) +#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 < 7) +#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 #endif /* AVFILTER_VERSION_H */ diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c index bf3082485..c042698ef 100644 --- a/libavfilter/vf_aspect.c +++ b/libavfilter/vf_aspect.c @@ -61,35 +61,9 @@ typedef struct AspectContext { AVRational dar; AVRational sar; int max; -#if FF_API_OLD_FILTER_OPTS - float aspect_den; -#endif char *ratio_expr; } AspectContext; -static av_cold int init(AVFilterContext *ctx) -{ -#if FF_API_OLD_FILTER_OPTS - AspectContext *s = ctx->priv; - int ret; - - if (s->ratio_expr && s->aspect_den > 0) { - double num; - av_log(ctx, AV_LOG_WARNING, - "num:den syntax is deprecated, please use num/den or named options instead\n"); - ret = av_expr_parse_and_eval(&num, s->ratio_expr, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, 0, ctx); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Unable to parse ratio numerator \"%s\"\n", s->ratio_expr); - return AVERROR(EINVAL); - } - s->sar = s->dar = av_d2q(num / s->aspect_den, s->max); - } -#endif - - return 0; -} - static int filter_frame(AVFilterLink *link, AVFrame *frame) { AspectContext *s = link->dst->priv; @@ -151,38 +125,34 @@ static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio) #if CONFIG_SETDAR_FILTER -static int setdar_config_props(AVFilterLink *inlink) +static int setdar_config_props(AVFilterLink *outlink) { - AspectContext *s = inlink->dst->priv; + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AspectContext *s = ctx->priv; AVRational dar; AVRational old_dar; AVRational old_sar = inlink->sample_aspect_ratio; int ret; -#if FF_API_OLD_FILTER_OPTS - if (!(s->ratio_expr && s->aspect_den > 0)) { -#endif if ((ret = get_aspect_ratio(inlink, &s->dar))) return ret; -#if FF_API_OLD_FILTER_OPTS - } -#endif if (s->dar.num && s->dar.den) { av_reduce(&s->sar.num, &s->sar.den, s->dar.num * inlink->h, s->dar.den * inlink->w, INT_MAX); - inlink->sample_aspect_ratio = s->sar; + outlink->sample_aspect_ratio = s->sar; dar = s->dar; } else { - inlink->sample_aspect_ratio = (AVRational){ 1, 1 }; + outlink->sample_aspect_ratio = (AVRational){ 1, 1 }; dar = (AVRational){ inlink->w, inlink->h }; } compute_dar(&old_dar, old_sar, inlink->w, inlink->h); - av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d dar:%d/%d sar:%d/%d -> dar:%d/%d sar:%d/%d\n", + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d dar:%d/%d sar:%d/%d -> dar:%d/%d sar:%d/%d\n", inlink->w, inlink->h, old_dar.num, old_dar.den, old_sar.num, old_sar.den, - dar.num, dar.den, inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den); + dar.num, dar.den, outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den); return 0; } @@ -191,9 +161,6 @@ static const AVOption setdar_options[] = { { "dar", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "ratio", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "r", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, -#if FF_API_OLD_FILTER_OPTS - { "dar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS }, -#endif { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS }, { NULL } }; @@ -204,7 +171,6 @@ static const AVFilterPad avfilter_vf_setdar_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .config_props = setdar_config_props, .filter_frame = filter_frame, }, { NULL } @@ -214,6 +180,7 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, + .config_props = setdar_config_props, }, { NULL } }; @@ -221,7 +188,6 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = { AVFilter ff_vf_setdar = { .name = "setdar", .description = NULL_IF_CONFIG_SMALL("Set the frame display aspect ratio."), - .init = init, .priv_size = sizeof(AspectContext), .priv_class = &setdar_class, .inputs = avfilter_vf_setdar_inputs, @@ -232,29 +198,25 @@ AVFilter ff_vf_setdar = { #if CONFIG_SETSAR_FILTER -static int setsar_config_props(AVFilterLink *inlink) +static int setsar_config_props(AVFilterLink *outlink) { - AspectContext *s = inlink->dst->priv; + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AspectContext *s = ctx->priv; AVRational old_sar = inlink->sample_aspect_ratio; AVRational old_dar, dar; int ret; -#if FF_API_OLD_FILTER_OPTS - if (!(s->ratio_expr && s->aspect_den > 0)) { -#endif if ((ret = get_aspect_ratio(inlink, &s->sar))) return ret; -#if FF_API_OLD_FILTER_OPTS - } -#endif - inlink->sample_aspect_ratio = s->sar; + outlink->sample_aspect_ratio = s->sar; compute_dar(&old_dar, old_sar, inlink->w, inlink->h); compute_dar(&dar, s->sar, inlink->w, inlink->h); - av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d dar:%d/%d -> sar:%d/%d dar:%d/%d\n", + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d dar:%d/%d -> sar:%d/%d dar:%d/%d\n", inlink->w, inlink->h, old_sar.num, old_sar.den, old_dar.num, old_dar.den, - inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, dar.num, dar.den); + outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, dar.num, dar.den); return 0; } @@ -263,9 +225,6 @@ static const AVOption setsar_options[] = { { "sar", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, -#if FF_API_OLD_FILTER_OPTS - { "sar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS }, -#endif { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS }, { NULL } }; @@ -276,7 +235,6 @@ static const AVFilterPad avfilter_vf_setsar_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .config_props = setsar_config_props, .filter_frame = filter_frame, }, { NULL } @@ -286,6 +244,7 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, + .config_props = setsar_config_props, }, { NULL } }; @@ -293,7 +252,6 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = { AVFilter ff_vf_setsar = { .name = "setsar", .description = NULL_IF_CONFIG_SMALL("Set the pixel sample aspect ratio."), - .init = init, .priv_size = sizeof(AspectContext), .priv_class = &setsar_class, .inputs = avfilter_vf_setsar_inputs, diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c index 054c0d55d..70c37c75d 100644 --- a/libavfilter/vf_blend.c +++ b/libavfilter/vf_blend.c @@ -524,19 +524,12 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (toplink->w != bottomlink->w || - toplink->h != bottomlink->h || - toplink->sample_aspect_ratio.num != bottomlink->sample_aspect_ratio.num || - toplink->sample_aspect_ratio.den != bottomlink->sample_aspect_ratio.den) { + if (toplink->w != bottomlink->w || toplink->h != bottomlink->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d)\n", ctx->input_pads[TOP].name, toplink->w, toplink->h, - toplink->sample_aspect_ratio.num, - toplink->sample_aspect_ratio.den, - ctx->input_pads[BOTTOM].name, bottomlink->w, bottomlink->h, - bottomlink->sample_aspect_ratio.num, - bottomlink->sample_aspect_ratio.den); + ctx->input_pads[BOTTOM].name, bottomlink->w, bottomlink->h); return AVERROR(EINVAL); } } diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c index 602031999..d7f8bf8a6 100644 --- a/libavfilter/vf_convolution.c +++ b/libavfilter/vf_convolution.c @@ -48,7 +48,7 @@ typedef struct ConvolutionContext { int nb_threads; int planewidth[4]; int planeheight[4]; - int matrix[4][25]; + int matrix[4][49]; int matrix_length[4]; int copy[4]; @@ -86,6 +86,14 @@ static const int same5x5[25] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const int same7x7[49] = {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, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0}; + static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { @@ -585,6 +593,81 @@ static int filter16_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } +static int filter16_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolutionContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int plane = td->plane; + const int peak = (1 << s->depth) - 1; + const int stride = in->linesize[plane] / 2; + const int bstride = s->bstride; + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; + uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); + uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 32; + uint16_t *p1 = p0 + bstride; + uint16_t *p2 = p1 + bstride; + uint16_t *p3 = p2 + bstride; + uint16_t *p4 = p3 + bstride; + uint16_t *p5 = p4 + bstride; + uint16_t *p6 = p5 + bstride; + uint16_t *orig = p0, *end = p6; + const int *matrix = s->matrix[plane]; + float rdiv = s->rdiv[plane]; + float bias = s->bias[plane]; + int y, x, i; + + line_copy16(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3); + line_copy16(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3); + line_copy16(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3); + line_copy16(p3, src, width, 3); + src += stride; + line_copy16(p4, src, width, 3); + src += stride; + line_copy16(p5, src, width, 3); + + for (y = slice_start; y < slice_end; y++) { + uint16_t *array[] = { + p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3, + p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3, + p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3, + p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3, + p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3, + p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3, + p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3, + }; + + src += stride * (y < height - 3 ? 1 : -1); + line_copy16(p6, src, width, 3); + + for (x = 0; x < width; x++) { + int sum = 0; + + for (i = 0; i < 25; i++) { + sum += *(array[i] + x) * matrix[i]; + } + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip(sum, 0, peak); + } + + p0 = p1; + p1 = p2; + p2 = p3; + p3 = p4; + p4 = p5; + p5 = p6; + p6 = (p6 == end) ? orig: p6 + bstride; + dst += out->linesize[plane] / 2; + } + + return 0; +} + static int filter_3x3(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ConvolutionContext *s = ctx->priv; @@ -705,6 +788,80 @@ static int filter_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } +static int filter_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolutionContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int plane = td->plane; + const int stride = in->linesize[plane]; + const int bstride = s->bstride; + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + const uint8_t *src = in->data[plane] + slice_start * stride; + uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; + uint8_t *p0 = s->bptrs[jobnr] + 32; + uint8_t *p1 = p0 + bstride; + uint8_t *p2 = p1 + bstride; + uint8_t *p3 = p2 + bstride; + uint8_t *p4 = p3 + bstride; + uint8_t *p5 = p4 + bstride; + uint8_t *p6 = p5 + bstride; + uint8_t *orig = p0, *end = p6; + const int *matrix = s->matrix[plane]; + float rdiv = s->rdiv[plane]; + float bias = s->bias[plane]; + int y, x, i; + + line_copy8(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3); + line_copy8(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3); + line_copy8(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3); + line_copy8(p3, src, width, 3); + src += stride; + line_copy8(p4, src, width, 3); + src += stride; + line_copy8(p5, src, width, 3); + + for (y = slice_start; y < slice_end; y++) { + uint8_t *array[] = { + p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3, + p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3, + p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3, + p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3, + p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3, + p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3, + p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3, + }; + + src += stride * (y < height - 3 ? 1 : -1); + line_copy8(p6, src, width, 3); + + for (x = 0; x < width; x++) { + int sum = 0; + + for (i = 0; i < 49; i++) { + sum += *(array[i] + x) * matrix[i]; + } + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip_uint8(sum); + } + + p0 = p1; + p1 = p2; + p2 = p3; + p3 = p4; + p4 = p5; + p5 = p6; + p6 = (p6 == end) ? orig: p6 + bstride; + dst += out->linesize[plane]; + } + + return 0; +} + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -725,14 +882,14 @@ static int config_input(AVFilterLink *inlink) if (!s->bptrs) return AVERROR(ENOMEM); - s->bstride = s->planewidth[0] + 32; + s->bstride = s->planewidth[0] + 64; s->bpc = (s->depth + 7) / 8; - s->buffer = av_malloc_array(5 * s->bstride * s->nb_threads, s->bpc); + s->buffer = av_malloc_array(7 * s->bstride * s->nb_threads, s->bpc); if (!s->buffer) return AVERROR(ENOMEM); for (p = 0; p < s->nb_threads; p++) { - s->bptrs[p] = s->buffer + 5 * s->bstride * s->bpc * p; + s->bptrs[p] = s->buffer + 7 * s->bstride * s->bpc * p; } if (!strcmp(ctx->filter->name, "convolution")) { @@ -742,6 +899,8 @@ static int config_input(AVFilterLink *inlink) s->filter[p] = filter16_3x3; else if (s->size[p] == 5) s->filter[p] = filter16_5x5; + else if (s->size[p] == 7) + s->filter[p] = filter16_7x7; } } } else if (!strcmp(ctx->filter->name, "prewitt")) { @@ -808,7 +967,7 @@ static av_cold int init(AVFilterContext *ctx) char *p, *arg, *saveptr = NULL; p = s->matrix_str[i]; - while (s->matrix_length[i] < 25) { + while (s->matrix_length[i] < 49) { if (!(arg = av_strtok(p, " ", &saveptr))) break; @@ -829,6 +988,12 @@ static av_cold int init(AVFilterContext *ctx) s->copy[i] = 1; else s->filter[i] = filter_5x5; + } else if (s->matrix_length[i] == 49) { + s->size[i] = 7; + if (!memcmp(matrix, same7x7, sizeof(same7x7))) + s->copy[i] = 1; + else + s->filter[i] = filter_7x7; } else { return AVERROR(EINVAL); } diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c index e00a44d63..982eda1cb 100644 --- a/libavfilter/vf_convolve.c +++ b/libavfilter/vf_convolve.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -29,12 +31,14 @@ #include "internal.h" #include "video.h" +#define MAX_THREADS 16 + typedef struct ConvolveContext { const AVClass *class; FFFrameSync fs; - FFTContext *fft[4]; - FFTContext *ifft[4]; + FFTContext *fft[4][MAX_THREADS]; + FFTContext *ifft[4][MAX_THREADS]; int fft_bits[4]; int fft_len[4]; @@ -49,8 +53,11 @@ typedef struct ConvolveContext { int depth; int planes; int impulse; + float noise; int nb_planes; int got_impulse[4]; + + int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } ConvolveContext; #define OFFSET(x) offsetof(ConvolveContext, x) @@ -61,11 +68,10 @@ static const AVOption convolve_options[] = { { "impulse", "when to process impulses", OFFSET(impulse), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "impulse" }, { "first", "process only first impulse, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "impulse" }, { "all", "process all impulses", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "impulse" }, + { "noise", "set noise", OFFSET(noise), AV_OPT_TYPE_FLOAT, {.dbl=0.0000001}, 0, 1, FLAGS }, { NULL }, }; -FRAMESYNC_DEFINE_CLASS(convolve, ConvolveContext, fs); - static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pixel_fmts_fftfilt[] = { @@ -112,7 +118,7 @@ static int config_input_main(AVFilterLink *inlink) for (i = 0; i < s->nb_planes; i++) { int w = s->planewidth[i]; int h = s->planeheight[i]; - int n = FFMAX(w, h) * 10/9; + int n = FFMAX(w, h); for (fft_bits = 1; 1 << fft_bits < n; fft_bits++); @@ -152,108 +158,290 @@ static int config_input_impulse(AVFilterLink *inlink) return 0; } -static void fft_horizontal(ConvolveContext *s, FFTComplex *fft_hdata, - AVFrame *in, int w, int h, int n, int plane, float scale) +typedef struct ThreadData { + FFTComplex *hdata, *vdata; + int plane, n; +} ThreadData; + +static int fft_horizontal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - int y, x; + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y; - for (y = 0; y < h; y++) { - if (s->depth == 8) { - const uint8_t *src = in->data[plane] + in->linesize[plane] * y; - - for (x = 0; x < w; x++) { - fft_hdata[y * n + x].re = src[x] * scale; - fft_hdata[y * n + x].im = 0; - } - } else { - const uint16_t *src = (const uint16_t *)(in->data[plane] + in->linesize[plane] * y); - - for (x = 0; x < w; x++) { - fft_hdata[y * n + x].re = src[x] * scale; - fft_hdata[y * n + x].im = 0; - } - } - for (; x < n; x++) { - fft_hdata[y * n + x].re = 0; - fft_hdata[y * n + x].im = 0; - } + for (y = start; y < end; y++) { + av_fft_permute(s->fft[plane][jobnr], hdata + y * n); + av_fft_calc(s->fft[plane][jobnr], hdata + y * n); } - for (; y < n; y++) { - for (x = 0; x < n; x++) { - fft_hdata[y * n + x].re = 0; - fft_hdata[y * n + x].im = 0; - } - } - - for (y = 0; y < n; y++) { - av_fft_permute(s->fft[plane], fft_hdata + y * n); - av_fft_calc(s->fft[plane], fft_hdata + y * n); - } + return 0; } -static void fft_vertical(ConvolveContext *s, FFTComplex *fft_hdata, FFTComplex *fft_vdata, - int n, int plane) +static void get_input(ConvolveContext *s, FFTComplex *fft_hdata, + AVFrame *in, int w, int h, int n, int plane, float scale) { + const int iw = (n - w) / 2, ih = (n - h) / 2; int y, x; - for (y = 0; y < n; y++) { - for (x = 0; x < n; x++) { - fft_vdata[y * n + x].re = fft_hdata[x * n + y].re; - fft_vdata[y * n + x].im = fft_hdata[x * n + y].im; - } - for (; x < n; x++) { - fft_vdata[y * n + x].re = 0; - fft_vdata[y * n + x].im = 0; - } - av_fft_permute(s->fft[plane], fft_vdata + y * n); - av_fft_calc(s->fft[plane], fft_vdata + y * n); - } -} - -static void ifft_vertical(ConvolveContext *s, int n, int plane) -{ - int y, x; - - for (y = 0; y < n; y++) { - av_fft_permute(s->ifft[plane], s->fft_vdata[plane] + y * n); - av_fft_calc(s->ifft[plane], s->fft_vdata[plane] + y * n); - for (x = 0; x < n; x++) { - s->fft_hdata[plane][x * n + y].re = s->fft_vdata[plane][y * n + x].re; - s->fft_hdata[plane][x * n + y].im = s->fft_vdata[plane][y * n + x].im; - } - } -} - -static void ifft_horizontal(ConvolveContext *s, AVFrame *out, - int w, int h, int n, int plane) -{ - const float scale = 1.f / (n * n); - const int max = (1 << s->depth) - 1; - const int oh = h / 2; - const int ow = w / 2; - int y, x; - - for (y = 0; y < n; y++) { - av_fft_permute(s->ifft[plane], s->fft_hdata[plane] + y * n); - av_fft_calc(s->ifft[plane], s->fft_hdata[plane] + y * n); - } - if (s->depth == 8) { for (y = 0; y < h; y++) { - uint8_t *dst = out->data[plane] + y * out->linesize[plane]; - for (x = 0; x < w; x++) - dst[x] = av_clip_uint8(s->fft_hdata[plane][(y+oh) * n + x+ow].re * scale); + const uint8_t *src = in->data[plane] + in->linesize[plane] * y; + + for (x = 0; x < w; x++) { + fft_hdata[(y + ih) * n + iw + x].re = src[x] * scale; + fft_hdata[(y + ih) * n + iw + x].im = 0; + } + + for (x = 0; x < iw; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + iw].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + + for (x = n - iw; x < n; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + n - iw - 1].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + } + + for (y = 0; y < ih; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[ih * n + x].re; + fft_hdata[y * n + x].im = 0; + } + } + + for (y = n - ih; y < n; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[(n - ih - 1) * n + x].re; + fft_hdata[y * n + x].im = 0; + } } } else { for (y = 0; y < h; y++) { - uint16_t *dst = (uint16_t *)(out->data[plane] + y * out->linesize[plane]); - for (x = 0; x < w; x++) - dst[x] = av_clip(s->fft_hdata[plane][(y+oh) * n + x+ow].re * scale, 0, max); + const uint16_t *src = (const uint16_t *)(in->data[plane] + in->linesize[plane] * y); + + for (x = 0; x < w; x++) { + fft_hdata[(y + ih) * n + iw + x].re = src[x] * scale; + fft_hdata[(y + ih) * n + iw + x].im = 0; + } + + for (x = 0; x < iw; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + iw].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + + for (x = n - iw; x < n; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + n - iw - 1].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + } + + for (y = 0; y < ih; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[ih * n + x].re; + fft_hdata[y * n + x].im = 0; + } + } + + for (y = n - ih; y < n; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[(n - ih - 1) * n + x].re; + fft_hdata[y * n + x].im = 0; + } } } } +static int fft_vertical(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + FFTComplex *vdata = td->vdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + for (x = 0; x < n; x++) { + vdata[y * n + x].re = hdata[x * n + y].re; + vdata[y * n + x].im = hdata[x * n + y].im; + } + + av_fft_permute(s->fft[plane][jobnr], vdata + y * n); + av_fft_calc(s->fft[plane][jobnr], vdata + y * n); + } + + return 0; +} + +static int ifft_vertical(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + FFTComplex *vdata = td->vdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + av_fft_permute(s->ifft[plane][jobnr], vdata + y * n); + av_fft_calc(s->ifft[plane][jobnr], vdata + y * n); + + for (x = 0; x < n; x++) { + hdata[x * n + y].re = vdata[y * n + x].re; + hdata[x * n + y].im = vdata[y * n + x].im; + } + } + + return 0; +} + +static int ifft_horizontal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y; + + for (y = start; y < end; y++) { + av_fft_permute(s->ifft[plane][jobnr], hdata + y * n); + av_fft_calc(s->ifft[plane][jobnr], hdata + y * n); + } + + return 0; +} + +static void get_output(ConvolveContext *s, FFTComplex *input, AVFrame *out, + int w, int h, int n, int plane, float scale) +{ + const int max = (1 << s->depth) - 1; + const int hh = h / 2; + const int hw = w / 2; + int y, x; + + if (s->depth == 8) { + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + (y + hh) * out->linesize[plane] + hw; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[y * n + x].re * scale); + } + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + (y + hh) * out->linesize[plane]; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[y * n + n - hw + x].re * scale); + } + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + y * out->linesize[plane] + hw; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[(n - hh + y) * n + x].re * scale); + } + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + y * out->linesize[plane]; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[(n - hh + y) * n + n - hw + x].re * scale); + } + } else { + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + (y + hh) * out->linesize[plane] + hw * 2); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[y * n + x].re * scale, 0, max); + } + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + (y + hh) * out->linesize[plane]); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[y * n + n - hw + x].re * scale, 0, max); + } + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + y * out->linesize[plane] + hw * 2); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[(n - hh + y) * n + x].re * scale, 0, max); + } + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + y * out->linesize[plane]); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[(n - hh + y) * n + n - hw + x].re * scale, 0, max); + } + } +} + +static int complex_multiply(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *input = td->hdata; + FFTComplex *filter = td->vdata; + const float noise = s->noise; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + int yn = y * n; + + for (x = 0; x < n; x++) { + FFTSample re, im, ire, iim; + + re = input[yn + x].re; + im = input[yn + x].im; + ire = filter[yn + x].re + noise; + iim = filter[yn + x].im; + + input[yn + x].re = ire * re - iim * im; + input[yn + x].im = iim * re + ire * im; + } + } + + return 0; +} + +static int complex_divide(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *input = td->hdata; + FFTComplex *filter = td->vdata; + const float noise = s->noise; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + int yn = y * n; + + for (x = 0; x < n; x++) { + FFTSample re, im, ire, iim, div; + + re = input[yn + x].re; + im = input[yn + x].im; + ire = filter[yn + x].re; + iim = filter[yn + x].im; + div = ire * ire + iim * iim + noise; + + input[yn + x].re = (ire * re + iim * im) / div; + input[yn + x].im = (ire * im - iim * re) / div; + } + } + + return 0; +} + static int do_convolve(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; @@ -269,18 +457,26 @@ static int do_convolve(FFFrameSync *fs) return ff_filter_frame(outlink, mainpic); for (plane = 0; plane < s->nb_planes; plane++) { + FFTComplex *filter = s->fft_vdata_impulse[plane]; + FFTComplex *input = s->fft_vdata[plane]; const int n = s->fft_len[plane]; const int w = s->planewidth[plane]; const int h = s->planeheight[plane]; float total = 0; + ThreadData td; if (!(s->planes & (1 << plane))) { continue; } - fft_horizontal(s, s->fft_hdata[plane], mainpic, w, h, n, plane, 1.f); - fft_vertical(s, s->fft_hdata[plane], s->fft_vdata[plane], - n, plane); + td.plane = plane, td.n = n; + get_input(s, s->fft_hdata[plane], mainpic, w, h, n, plane, 1.f); + + td.hdata = s->fft_hdata[plane]; + td.vdata = s->fft_vdata[plane]; + + ctx->internal->execute(ctx, fft_horizontal, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, fft_vertical, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); if ((!s->impulse && !s->got_impulse[plane]) || s->impulse) { if (s->depth == 8) { @@ -300,29 +496,29 @@ static int do_convolve(FFFrameSync *fs) } total = FFMAX(1, total); - fft_horizontal(s, s->fft_hdata_impulse[plane], impulsepic, w, h, n, plane, 1 / total); - fft_vertical(s, s->fft_hdata_impulse[plane], s->fft_vdata_impulse[plane], - n, plane); + get_input(s, s->fft_hdata_impulse[plane], impulsepic, w, h, n, plane, 1.f / total); + + td.hdata = s->fft_hdata_impulse[plane]; + td.vdata = s->fft_vdata_impulse[plane]; + + ctx->internal->execute(ctx, fft_horizontal, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, fft_vertical, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); s->got_impulse[plane] = 1; } - for (y = 0; y < n; y++) { - for (x = 0; x < n; x++) { - FFTSample re, im, ire, iim; + td.hdata = input; + td.vdata = filter; - re = s->fft_vdata[plane][y*n + x].re; - im = s->fft_vdata[plane][y*n + x].im; - ire = s->fft_vdata_impulse[plane][y*n + x].re; - iim = s->fft_vdata_impulse[plane][y*n + x].im; + ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); - s->fft_vdata[plane][y*n + x].re = ire * re - iim * im; - s->fft_vdata[plane][y*n + x].im = iim * re + ire * im; - } - } + td.hdata = s->fft_hdata[plane]; + td.vdata = s->fft_vdata[plane]; - ifft_vertical(s, n, plane); - ifft_horizontal(s, mainpic, w, h, n, plane); + ctx->internal->execute(ctx, ifft_vertical, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, ifft_horizontal, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + + get_output(s, s->fft_hdata[plane], mainpic, w, h, n, plane, 1.f / (n * n)); } return ff_filter_frame(outlink, mainpic); @@ -333,7 +529,7 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; ConvolveContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; - int ret, i; + int ret, i, j; s->fs.on_event = do_convolve; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -349,10 +545,12 @@ static int config_output(AVFilterLink *outlink) return ret; for (i = 0; i < s->nb_planes; i++) { - s->fft[i] = av_fft_init(s->fft_bits[i], 0); - s->ifft[i] = av_fft_init(s->fft_bits[i], 1); - if (!s->fft[i] || !s->ifft[i]) - return AVERROR(ENOMEM); + for (j = 0; j < MAX_THREADS; j++) { + s->fft[i][j] = av_fft_init(s->fft_bits[i], 0); + s->ifft[i][j] = av_fft_init(s->fft_bits[i], 1); + if (!s->fft[i][j] || !s->ifft[i][j]) + return AVERROR(ENOMEM); + } } return 0; @@ -364,18 +562,36 @@ static int activate(AVFilterContext *ctx) return ff_framesync_activate(&s->fs); } +static av_cold int init(AVFilterContext *ctx) +{ + ConvolveContext *s = ctx->priv; + + if (!strcmp(ctx->filter->name, "convolve")) { + s->filter = complex_multiply; + } else if (!strcmp(ctx->filter->name, "deconvolve")) { + s->filter = complex_divide; + } else { + return AVERROR_BUG; + } + + return 0; +} + static av_cold void uninit(AVFilterContext *ctx) { ConvolveContext *s = ctx->priv; - int i; + int i, j; for (i = 0; i < 4; i++) { av_freep(&s->fft_hdata[i]); av_freep(&s->fft_vdata[i]); av_freep(&s->fft_hdata_impulse[i]); av_freep(&s->fft_vdata_impulse[i]); - av_fft_end(s->fft[i]); - av_fft_end(s->ifft[i]); + + for (j = 0; j < MAX_THREADS; j++) { + av_fft_end(s->fft[i][j]); + av_fft_end(s->ifft[i][j]); + } } ff_framesync_uninit(&s->fs); @@ -403,10 +619,15 @@ static const AVFilterPad convolve_outputs[] = { { NULL } }; +#if CONFIG_CONVOLVE_FILTER + +FRAMESYNC_DEFINE_CLASS(convolve, ConvolveContext, fs); + AVFilter ff_vf_convolve = { .name = "convolve", .description = NULL_IF_CONFIG_SMALL("Convolve first video stream with second video stream."), .preinit = convolve_framesync_preinit, + .init = init, .uninit = uninit, .query_formats = query_formats, .activate = activate, @@ -414,5 +635,37 @@ AVFilter ff_vf_convolve = { .priv_class = &convolve_class, .inputs = convolve_inputs, .outputs = convolve_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; + +#endif /* CONFIG_CONVOLVE_FILTER */ + +#if CONFIG_DECONVOLVE_FILTER + +static const AVOption deconvolve_options[] = { + { "planes", "set planes to deconvolve", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS }, + { "impulse", "when to process impulses", OFFSET(impulse), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "impulse" }, + { "first", "process only first impulse, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "impulse" }, + { "all", "process all impulses", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "impulse" }, + { "noise", "set noise", OFFSET(noise), AV_OPT_TYPE_FLOAT, {.dbl=0.0000001}, 0, 1, FLAGS }, + { NULL }, +}; + +FRAMESYNC_DEFINE_CLASS(deconvolve, ConvolveContext, fs); + +AVFilter ff_vf_deconvolve = { + .name = "deconvolve", + .description = NULL_IF_CONFIG_SMALL("Deconvolve first video stream with second video stream."), + .preinit = deconvolve_framesync_preinit, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .activate = activate, + .priv_size = sizeof(ConvolveContext), + .priv_class = &deconvolve_class, + .inputs = convolve_inputs, + .outputs = convolve_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, +}; + +#endif /* CONFIG_DECONVOLVE_FILTER */ diff --git a/libavfilter/vf_deinterlace_qsv.c b/libavfilter/vf_deinterlace_qsv.c index 2810bffe4..897e6bd62 100644 --- a/libavfilter/vf_deinterlace_qsv.c +++ b/libavfilter/vf_deinterlace_qsv.c @@ -68,13 +68,18 @@ typedef struct QSVDeintContext { int nb_surface_ptrs; mfxExtOpaqueSurfaceAlloc opaque_alloc; - mfxExtBuffer *ext_buffers[1]; + mfxExtVPPDeinterlacing deint_conf; + mfxExtBuffer *ext_buffers[2]; + int num_ext_buffers; QSVFrame *work_frames; int64_t last_pts; int eof; + + /* option for Deinterlacing algorithm to be used */ + int mode; } QSVDeintContext; static void qsvdeint_uninit(AVFilterContext *ctx) @@ -212,6 +217,12 @@ static int init_out_session(AVFilterContext *ctx) memset(&par, 0, sizeof(par)); + s->deint_conf.Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING; + s->deint_conf.Header.BufferSz = sizeof(s->deint_conf); + s->deint_conf.Mode = s->mode; + + s->ext_buffers[s->num_ext_buffers++] = (mfxExtBuffer *)&s->deint_conf; + if (opaque) { s->surface_ptrs = av_mallocz_array(hw_frames_hwctx->nb_surfaces, sizeof(*s->surface_ptrs)); @@ -230,10 +241,7 @@ static int init_out_session(AVFilterContext *ctx) 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; - - par.ExtParam = s->ext_buffers; - par.NumExtParam = FF_ARRAY_ELEMS(s->ext_buffers); + s->ext_buffers[s->num_ext_buffers++] = (mfxExtBuffer *)&s->opaque_alloc; par.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; } else { @@ -261,6 +269,9 @@ static int init_out_session(AVFilterContext *ctx) par.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; } + par.ExtParam = s->ext_buffers; + par.NumExtParam = s->num_ext_buffers; + par.AsyncDepth = 1; // TODO async par.vpp.In = hw_frames_hwctx->surfaces[0].Info; @@ -529,6 +540,9 @@ static int qsvdeint_request_frame(AVFilterLink *outlink) #define OFFSET(x) offsetof(QSVDeintContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption options[] = { + { "mode", "set deinterlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MFX_DEINTERLACING_ADVANCED}, MFX_DEINTERLACING_BOB, MFX_DEINTERLACING_ADVANCED, FLAGS, "mode"}, + { "bob", "bob algorithm", 0, AV_OPT_TYPE_CONST, {.i64 = MFX_DEINTERLACING_BOB}, MFX_DEINTERLACING_BOB, MFX_DEINTERLACING_ADVANCED, FLAGS, "mode"}, + { "advanced", "Motion adaptive algorithm", 0, AV_OPT_TYPE_CONST, {.i64 = MFX_DEINTERLACING_ADVANCED}, MFX_DEINTERLACING_BOB, MFX_DEINTERLACING_ADVANCED, FLAGS, "mode"}, { NULL }, }; diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c index 64b48c6d0..fb4eb355b 100644 --- a/libavfilter/vf_deshake.c +++ b/libavfilter/vf_deshake.c @@ -60,7 +60,6 @@ #include "libavutil/qsort.h" #include "deshake.h" -#include "deshake_opencl.h" #define OFFSET(x) offsetof(DeshakeContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -83,7 +82,7 @@ static const AVOption deshake_options[] = { { "exhaustive", "exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" }, { "less", "less exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=SMART_EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" }, { "filename", "set motion search detailed log file name", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, - { "opencl", "use OpenCL filtering capabilities", OFFSET(opencl), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { "opencl", "ignored", OFFSET(opencl), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, { NULL } }; @@ -341,7 +340,6 @@ static int deshake_transform_c(AVFilterContext *ctx, static av_cold int init(AVFilterContext *ctx) { - int ret; DeshakeContext *deshake = ctx->priv; deshake->sad = av_pixelutils_get_sad_fn(4, 4, 1, deshake); // 16x16, 2nd source unaligned @@ -369,17 +367,7 @@ static av_cold int init(AVFilterContext *ctx) deshake->cx &= ~15; } deshake->transform = deshake_transform_c; - if (!CONFIG_OPENCL && deshake->opencl) { - av_log(ctx, AV_LOG_ERROR, "OpenCL support was not enabled in this build, cannot be selected\n"); - return AVERROR(EINVAL); - } - if (CONFIG_OPENCL && deshake->opencl) { - deshake->transform = ff_opencl_transform; - ret = ff_opencl_deshake_init(ctx); - if (ret < 0) - return ret; - } av_log(ctx, AV_LOG_VERBOSE, "cx: %d, cy: %d, cw: %d, ch: %d, rx: %d, ry: %d, edge: %d blocksize: %d contrast: %d search: %d\n", deshake->cx, deshake->cy, deshake->cw, deshake->ch, deshake->rx, deshake->ry, deshake->edge, deshake->blocksize * 2, deshake->contrast, deshake->search); @@ -416,9 +404,6 @@ static int config_props(AVFilterLink *link) static av_cold void uninit(AVFilterContext *ctx) { DeshakeContext *deshake = ctx->priv; - if (CONFIG_OPENCL && deshake->opencl) { - ff_opencl_deshake_uninit(ctx); - } av_frame_free(&deshake->ref); av_freep(&deshake->angles); deshake->angles_size = 0; @@ -447,12 +432,6 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) } av_frame_copy_props(out, in); - if (CONFIG_OPENCL && deshake->opencl) { - ret = ff_opencl_deshake_process_inout_buf(link->dst,in, out); - if (ret < 0) - goto fail; - } - if (deshake->cx < 0 || deshake->cy < 0 || deshake->cw < 0 || deshake->ch < 0) { // Find the most likely global motion for the current frame find_motion(deshake, (deshake->ref == NULL) ? in->data[0] : deshake->ref->data[0], in->data[0], link->w, link->h, in->linesize[0], &t); diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c index 88bb9ae5c..c9cb63dbd 100644 --- a/libavfilter/vf_drawbox.c +++ b/libavfilter/vf_drawbox.c @@ -47,7 +47,7 @@ static const char *const var_names[] = { "h", ///< height of the rendered box "w", ///< width of the rendered box "t", - "max", + "fill", NULL }; @@ -80,6 +80,7 @@ typedef struct DrawBoxContext { char *w_expr, *h_expr; ///< expression for width and height char *t_expr; ///< expression for thickness int have_alpha; + int replace; } DrawBoxContext; static const int NUM_EXPR_EVALS = 5; @@ -213,7 +214,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) int plane, x, y, xb = s->x, yb = s->y; unsigned char *row[4]; - if (s->have_alpha) { + if (s->have_alpha && s->replace) { for (y = FFMAX(yb, 0); y < frame->height && y < (yb + s->h); y++) { row[0] = frame->data[0] + y * frame->linesize[0]; row[3] = frame->data[3] + y * frame->linesize[3]; @@ -286,6 +287,7 @@ static const AVOption drawbox_options[] = { { "c", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "thickness", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "t", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "replace", "replace color & alpha", OFFSET(replace), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, FLAGS }, { NULL } }; @@ -354,7 +356,7 @@ static int drawgrid_filter_frame(AVFilterLink *inlink, AVFrame *frame) int plane, x, y; uint8_t *row[4]; - if (drawgrid->have_alpha) { + if (drawgrid->have_alpha && drawgrid->replace) { for (y = 0; y < frame->height; y++) { row[0] = frame->data[0] + y * frame->linesize[0]; row[3] = frame->data[3] + y * frame->linesize[3]; @@ -418,6 +420,7 @@ static const AVOption drawgrid_options[] = { { "c", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "thickness", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS }, { "t", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS }, + { "replace", "replace color & alpha", OFFSET(replace), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, FLAGS }, { NULL } }; diff --git a/libavfilter/vf_entropy.c b/libavfilter/vf_entropy.c new file mode 100644 index 000000000..e6002ce27 --- /dev/null +++ b/libavfilter/vf_entropy.c @@ -0,0 +1,206 @@ +/* + * 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 "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "drawutils.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct EntropyContext { + const AVClass *class; + + int mode; + + int nb_planes; + int planeheight[4]; + int planewidth[4]; + int depth; + int is_rgb; + uint8_t rgba_map[4]; + char planenames[4]; + int64_t *histogram; +} EntropyContext; + +#define OFFSET(x) offsetof(EntropyContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVOption entropy_options[] = { + { "mode", "set kind of histogram entropy measurement", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "mode" }, + { "normal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" }, + { "diff", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(entropy); + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixfmts[] = { + AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9, + AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV420P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE + }; + + AVFilterFormats *formats = ff_make_format_list(pixfmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +static int config_input(AVFilterLink *inlink) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + AVFilterContext *ctx = inlink->dst; + EntropyContext *s = ctx->priv; + + s->nb_planes = desc->nb_components; + + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + s->depth = desc->comp[0].depth; + s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0; + + s->planenames[0] = s->is_rgb ? 'R' : 'Y'; + s->planenames[1] = s->is_rgb ? 'G' : 'U'; + s->planenames[2] = s->is_rgb ? 'B' : 'V'; + s->planenames[3] = 'A'; + + s->histogram = av_malloc_array(1 << s->depth, sizeof(*s->histogram)); + if (!s->histogram) + return AVERROR(ENOMEM); + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + EntropyContext *s = ctx->priv; + int plane, y, x; + + for (plane = 0; plane < s->nb_planes; plane++) { + int cidx = s->is_rgb ? s->rgba_map[plane] : plane; + const uint8_t *src8 = in->data[plane]; + const uint16_t *src16 = (const uint16_t *)in->data[plane]; + float total = s->planewidth[plane] * s->planeheight[plane]; + float entropy = 0; + char metabuf[128]; + char key[128]; + + memset(s->histogram, 0, (1 << s->depth) * sizeof(*s->histogram)); + + if (s->depth <= 8) { + for (y = 0; y < s->planeheight[plane]; y++) { + for (x = 0; x < s->planewidth[plane]; x++) { + s->histogram[src8[x]]++; + } + + src8 += in->linesize[plane]; + } + } else { + for (y = 0; y < s->planeheight[plane]; y++) { + for (x = 0; x < s->planewidth[plane]; x++) { + s->histogram[src16[x]]++; + } + + src16 += in->linesize[plane] / 2; + } + } + + for (y = 0; y < 1 << s->depth; y++) { + if (s->mode == 0) { + if (s->histogram[y]) { + float p = s->histogram[y] / total; + entropy += -log2(p) * p; + } + } else if (s->mode == 1) { + if (y && (s->histogram[y] - s->histogram[y - 1]) != 0) { + float p = FFABS(s->histogram[y] - s->histogram[y - 1]) / total; + entropy += -log2(p) * p; + } + } + } + + snprintf(key, sizeof(key), "lavfi.entropy.entropy.%s.%c", s->mode ? "diff" : "normal", s->planenames[cidx]); + snprintf(metabuf, sizeof(metabuf), "%f", entropy); + av_dict_set(&in->metadata, key, metabuf, 0); + snprintf(key, sizeof(key), "lavfi.entropy.normalized_entropy.%s.%c", s->mode ? "diff" : "normal", s->planenames[cidx]); + snprintf(metabuf, sizeof(metabuf), "%f", entropy / log2(1 << s->depth)); + av_dict_set(&in->metadata, key, metabuf, 0); + } + + return ff_filter_frame(outlink, in); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + EntropyContext *s = ctx->priv; + + av_freep(&s->histogram); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_entropy = { + .name = "entropy", + .description = NULL_IF_CONFIG_SMALL("Measure video frames entropy."), + .priv_size = sizeof(EntropyContext), + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, + .priv_class = &entropy_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_fftfilt.c b/libavfilter/vf_fftfilt.c index 7f60ca1f8..af44b1e22 100644 --- a/libavfilter/vf_fftfilt.c +++ b/libavfilter/vf_fftfilt.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2015 Arwa Arif + * Copyright (c) 2017 Paul B Mahol * * This file is part of FFmpeg. * @@ -64,6 +65,8 @@ typedef struct FFTFILTContext { AVExpr *weight_expr[MAX_PLANES]; double *weight[MAX_PLANES]; + void (*rdft_horizontal)(struct FFTFILTContext *s, AVFrame *in, int w, int h, int plane); + void (*irdft_horizontal)(struct FFTFILTContext *s, AVFrame *out, int w, int h, int plane); } FFTFILTContext; static const char *const var_names[] = { "X", "Y", "W", "H", "N", NULL }; @@ -111,7 +114,7 @@ static void copy_rev (FFTSample *dest, int w, int w2) } /*Horizontal pass - RDFT*/ -static void rdft_horizontal(FFTFILTContext *s, AVFrame *in, int w, int h, int plane) +static void rdft_horizontal8(FFTFILTContext *s, AVFrame *in, int w, int h, int plane) { int i, j; @@ -126,6 +129,23 @@ static void rdft_horizontal(FFTFILTContext *s, AVFrame *in, int w, int h, int pl av_rdft_calc(s->hrdft[plane], s->rdft_hdata[plane] + i * s->rdft_hlen[plane]); } +static void rdft_horizontal16(FFTFILTContext *s, AVFrame *in, int w, int h, int plane) +{ + const uint16_t *src = (const uint16_t *)in->data[plane]; + int linesize = in->linesize[plane] / 2; + int i, j; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) + s->rdft_hdata[plane][i * s->rdft_hlen[plane] + j] = *(src + linesize * i + j); + + copy_rev(s->rdft_hdata[plane] + i * s->rdft_hlen[plane], w, s->rdft_hlen[plane]); + } + + for (i = 0; i < h; i++) + av_rdft_calc(s->hrdft[plane], s->rdft_hdata[plane] + i * s->rdft_hlen[plane]); +} + /*Vertical pass - RDFT*/ static void rdft_vertical(FFTFILTContext *s, int h, int plane) { @@ -156,7 +176,7 @@ static void irdft_vertical(FFTFILTContext *s, int h, int plane) } /*Horizontal pass - IRDFT*/ -static void irdft_horizontal(FFTFILTContext *s, AVFrame *out, int w, int h, int plane) +static void irdft_horizontal8(FFTFILTContext *s, AVFrame *out, int w, int h, int plane) { int i, j; @@ -171,6 +191,24 @@ static void irdft_horizontal(FFTFILTContext *s, AVFrame *out, int w, int h, int s->rdft_vlen[plane]), 0, 255); } +static void irdft_horizontal16(FFTFILTContext *s, AVFrame *out, int w, int h, int plane) +{ + uint16_t *dst = (uint16_t *)out->data[plane]; + int linesize = out->linesize[plane] / 2; + int max = (1 << s->depth) - 1; + int i, j; + + for (i = 0; i < h; i++) + av_rdft_calc(s->ihrdft[plane], s->rdft_hdata[plane] + i * s->rdft_hlen[plane]); + + for (i = 0; i < h; i++) + for (j = 0; j < w; j++) + *(dst + linesize * i + j) = av_clip(s->rdft_hdata[plane][i + *s->rdft_hlen[plane] + j] * 4 / + (s->rdft_hlen[plane] * + s->rdft_vlen[plane]), 0, max); +} + static av_cold int initialize(AVFilterContext *ctx) { FFTFILTContext *s = ctx->priv; @@ -276,6 +314,16 @@ static int config_props(AVFilterLink *inlink) if (s->eval_mode == EVAL_MODE_INIT) do_eval(s, inlink, plane); } + + if (s->depth <= 8) { + s->rdft_horizontal = rdft_horizontal8; + s->irdft_horizontal = irdft_horizontal8; + } else if (s->depth > 8) { + s->rdft_horizontal = rdft_horizontal16; + s->irdft_horizontal = irdft_horizontal16; + } else { + return AVERROR_BUG; + } return 0; } @@ -302,7 +350,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->eval_mode == EVAL_MODE_FRAME) do_eval(s, inlink, plane); - rdft_horizontal(s, in, w, h, plane); + s->rdft_horizontal(s, in, w, h, plane); rdft_vertical(s, h, plane); /*Change user defined parameters*/ @@ -314,7 +362,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->rdft_vdata[plane][0] += s->rdft_hlen[plane] * s->rdft_vlen[plane] * s->dc[plane]; irdft_vertical(s, h, plane); - irdft_horizontal(s, out, w, h, plane); + s->irdft_horizontal(s, out, w, h, plane); } av_frame_free(&in); @@ -344,6 +392,15 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, + AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, + AV_PIX_FMT_YUV422P16, + AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV444P16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_fillborders.c b/libavfilter/vf_fillborders.c new file mode 100644 index 000000000..df883bc62 --- /dev/null +++ b/libavfilter/vf_fillborders.c @@ -0,0 +1,394 @@ +/* + * 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 "libavutil/colorspace.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "drawutils.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +enum { Y, U, V, A }; +enum { R, G, B }; + +enum FillMode { FM_SMEAR, FM_MIRROR, FM_FIXED, FM_NB_MODES }; + +typedef struct Borders { + int left, right, top, bottom; +} Borders; + +typedef struct FillBordersContext { + const AVClass *class; + int left, right, top, bottom; + int mode; + + int nb_planes; + int depth; + Borders borders[4]; + int planewidth[4]; + int planeheight[4]; + uint8_t fill[4]; + uint8_t yuv_color[4]; + uint8_t rgba_color[4]; + + void (*fillborders)(struct FillBordersContext *s, AVFrame *frame); +} FillBordersContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +static void smear_borders8(FillBordersContext *s, AVFrame *frame) +{ + int p, y; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *ptr = frame->data[p]; + int linesize = frame->linesize[p]; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + memset(ptr + y * linesize, + *(ptr + y * linesize + s->borders[p].left), + s->borders[p].left); + memset(ptr + y * linesize + s->planewidth[p] - s->borders[p].right, + *(ptr + y * linesize + s->planewidth[p] - s->borders[p].right - 1), + s->borders[p].right); + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + s->borders[p].top * linesize, s->planewidth[p]); + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + memcpy(ptr + y * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1) * linesize, + s->planewidth[p]); + } + } +} + +static void smear_borders16(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint16_t *ptr = (uint16_t *)frame->data[p]; + int linesize = frame->linesize[p] / 2; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = *(ptr + y * linesize + s->borders[p].left); + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = + *(ptr + y * linesize + s->planewidth[p] - s->borders[p].right - 1); + } + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + s->borders[p].top * linesize, s->planewidth[p] * 2); + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + memcpy(ptr + y * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1) * linesize, + s->planewidth[p] * 2); + } + } +} + +static void mirror_borders8(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *ptr = frame->data[p]; + int linesize = frame->linesize[p]; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - 1 - x]; + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = + ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 1 - x]; + } + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + (s->borders[p].top * 2 - 1 - y) * linesize, + s->planewidth[p]); + } + + for (y = 0; y < s->borders[p].bottom; y++) { + memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1 - y) * linesize, + s->planewidth[p]); + } + } +} + +static void mirror_borders16(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint16_t *ptr = (uint16_t *)frame->data[p]; + int linesize = frame->linesize[p] / 2; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - 1 - x]; + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = + ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 1 - x]; + } + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + (s->borders[p].top * 2 - 1 - y) * linesize, + s->planewidth[p] * 2); + } + + for (y = 0; y < s->borders[p].bottom; y++) { + memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1 - y) * linesize, + s->planewidth[p] * 2); + } + } +} + +static void fixed_borders8(FillBordersContext *s, AVFrame *frame) +{ + int p, y; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *ptr = frame->data[p]; + uint8_t fill = s->fill[p]; + int linesize = frame->linesize[p]; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + memset(ptr + y * linesize, fill, s->borders[p].left); + memset(ptr + y * linesize + s->planewidth[p] - s->borders[p].right, fill, + s->borders[p].right); + } + + for (y = 0; y < s->borders[p].top; y++) { + memset(ptr + y * linesize, fill, s->planewidth[p]); + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + memset(ptr + y * linesize, fill, s->planewidth[p]); + } + } +} + +static void fixed_borders16(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint16_t *ptr = (uint16_t *)frame->data[p]; + uint16_t fill = s->fill[p] << (s->depth - 8); + int linesize = frame->linesize[p] / 2; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = fill; + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = fill; + } + } + + for (y = 0; y < s->borders[p].top; y++) { + for (x = 0; x < s->planewidth[p]; x++) { + ptr[y * linesize + x] = fill; + } + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + for (x = 0; x < s->planewidth[p]; x++) { + ptr[y * linesize + x] = fill; + } + } + } +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + FillBordersContext *s = inlink->dst->priv; + + s->fillborders(s, frame); + + return ff_filter_frame(inlink->dst->outputs[0], frame); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + FillBordersContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + s->nb_planes = desc->nb_components; + s->depth = desc->comp[0].depth; + + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + s->borders[0].left = s->borders[3].left = s->left; + s->borders[0].right = s->borders[3].right = s->right; + s->borders[0].top = s->borders[3].top = s->top; + s->borders[0].bottom = s->borders[3].bottom = s->bottom; + + s->borders[1].left = s->left >> desc->log2_chroma_w; + s->borders[1].right = s->right >> desc->log2_chroma_w; + s->borders[1].top = s->top >> desc->log2_chroma_h; + s->borders[1].bottom = s->bottom >> desc->log2_chroma_h; + + s->borders[2].left = s->left >> desc->log2_chroma_w; + s->borders[2].right = s->right >> desc->log2_chroma_w; + s->borders[2].top = s->top >> desc->log2_chroma_h; + s->borders[2].bottom = s->bottom >> desc->log2_chroma_h; + + if (inlink->w < s->left + s->right || + inlink->w <= s->left || + inlink->w <= s->right || + inlink->h < s->top + s->bottom || + inlink->h <= s->top || + inlink->h <= s->bottom || + inlink->w < s->left * 2 || + inlink->w < s->right * 2 || + inlink->h < s->top * 2 || + inlink->h < s->bottom * 2) { + av_log(ctx, AV_LOG_ERROR, "Borders are bigger than input frame size.\n"); + return AVERROR(EINVAL); + } + + switch (s->mode) { + case FM_SMEAR: s->fillborders = s->depth <= 8 ? smear_borders8 : smear_borders16; break; + case FM_MIRROR: s->fillborders = s->depth <= 8 ? mirror_borders8 : mirror_borders16; break; + case FM_FIXED: s->fillborders = s->depth <= 8 ? fixed_borders8 : fixed_borders16; break; + } + + s->yuv_color[Y] = RGB_TO_Y_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B]); + s->yuv_color[U] = RGB_TO_U_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B], 0); + s->yuv_color[V] = RGB_TO_V_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B], 0); + s->yuv_color[A] = s->rgba_color[A]; + + if (desc->flags & AV_PIX_FMT_FLAG_RGB) { + uint8_t rgba_map[4]; + int i; + + ff_fill_rgba_map(rgba_map, inlink->format); + for (i = 0; i < 4; i++) + s->fill[rgba_map[i]] = s->rgba_color[i]; + } else { + memcpy(s->fill, s->yuv_color, sizeof(s->yuv_color)); + } + + return 0; +} + +#define OFFSET(x) offsetof(FillBordersContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption fillborders_options[] = { + { "left", "set the left fill border", OFFSET(left), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "right", "set the right fill border", OFFSET(right), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "top", "set the top fill border", OFFSET(top), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "bottom", "set the bottom fill border", OFFSET(bottom), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "mode", "set the fill borders mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=FM_SMEAR}, 0, FM_NB_MODES-1, FLAGS, "mode" }, + { "smear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_SMEAR}, 0, 0, FLAGS, "mode" }, + { "mirror", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_MIRROR}, 0, 0, FLAGS, "mode" }, + { "fixed", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_FIXED}, 0, 0, FLAGS, "mode" }, + { "color", "set the color for the fixed mode", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(fillborders); + +static const AVFilterPad fillborders_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + .filter_frame = filter_frame, + .needs_writable = 1, + }, + { NULL } +}; + +static const AVFilterPad fillborders_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_fillborders = { + .name = "fillborders", + .description = NULL_IF_CONFIG_SMALL("Fill borders of the input video."), + .priv_size = sizeof(FillBordersContext), + .priv_class = &fillborders_class, + .query_formats = query_formats, + .inputs = fillborders_inputs, + .outputs = fillborders_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_framepack.c b/libavfilter/vf_framepack.c index a5cd9540b..12a29964c 100644 --- a/libavfilter/vf_framepack.c +++ b/libavfilter/vf_framepack.c @@ -324,6 +324,8 @@ static int try_push_frame(AVFilterContext *ctx) if (!stereo) return AVERROR(ENOMEM); stereo->type = s->format; + stereo->view = i == LEFT ? AV_STEREO3D_VIEW_LEFT + : AV_STEREO3D_VIEW_RIGHT; // filter the frame and immediately relinquish its pointer ret = ff_filter_frame(outlink, s->input_views[i]); diff --git a/libavfilter/vf_framerate.c b/libavfilter/vf_framerate.c index dc8b05f40..a5ae6ddb7 100644 --- a/libavfilter/vf_framerate.c +++ b/libavfilter/vf_framerate.c @@ -39,45 +39,39 @@ #include "internal.h" #include "video.h" -#define N_SRCE 3 - typedef struct FrameRateContext { const AVClass *class; // parameters AVRational dest_frame_rate; ///< output frames per second int flags; ///< flags affecting frame rate conversion algorithm double scene_score; ///< score that denotes a scene change has happened - int interp_start; ///< start of range to apply linear interpolation - int interp_end; ///< end of range to apply linear interpolation + int interp_start; ///< start of range to apply linear interpolation (same bitdepth as input) + int interp_end; ///< end of range to apply linear interpolation (same bitdepth as input) + int interp_start_param; ///< start of range to apply linear interpolation + int interp_end_param; ///< end of range to apply linear interpolation int line_size[4]; ///< bytes of pixel data per line for each plane int vsub; - int frst, next, prev, crnt, last; - int pending_srce_frames; ///< how many input frames are still waiting to be processed - int flush; ///< are we flushing final frames - int pending_end_frame; ///< flag indicating we are waiting to call filter_frame() - AVRational srce_time_base; ///< timebase of source - AVRational dest_time_base; ///< timebase of destination - int32_t dest_frame_num; - int64_t last_dest_frame_pts; ///< pts of the last frame output - int64_t average_srce_pts_dest_delta;///< average input pts delta converted from input rate to output rate - int64_t average_dest_pts_delta; ///< calculated average output pts delta av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) double prev_mafd; ///< previous MAFD (scene detect only) - AVFrame *srce[N_SRCE]; ///< buffered source frames - int64_t srce_pts_dest[N_SRCE]; ///< pts for source frames scaled to output timebase - int64_t pts; ///< pts of frame we are working on - - int (*blend_frames)(AVFilterContext *ctx, float interpolate, - AVFrame *copy_src1, AVFrame *copy_src2); int max; int bitdepth; AVFrame *work; + + AVFrame *f0; ///< last frame + AVFrame *f1; ///< current frame + int64_t pts0; ///< last frame pts in dest_time_base + int64_t pts1; ///< current frame pts in dest_time_base + int64_t delta; ///< pts1 to pts0 delta + double score; ///< scene change score (f0 to f1) + int flush; ///< 1 if the filter is being flushed + int64_t start_pts; ///< pts of the first output frame + int64_t n; ///< output frame counter } FrameRateContext; #define OFFSET(x) offsetof(FrameRateContext, x) @@ -88,9 +82,9 @@ typedef struct FrameRateContext { static const AVOption framerate_options[] = { {"fps", "required output frames per second rate", OFFSET(dest_frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="50"}, 0, INT_MAX, V|F }, - {"interp_start", "point to start linear interpolation", OFFSET(interp_start), AV_OPT_TYPE_INT, {.i64=15}, 0, 255, V|F }, - {"interp_end", "point to end linear interpolation", OFFSET(interp_end), AV_OPT_TYPE_INT, {.i64=240}, 0, 255, V|F }, - {"scene", "scene change level", OFFSET(scene_score), AV_OPT_TYPE_DOUBLE, {.dbl=7.0}, 0, INT_MAX, V|F }, + {"interp_start", "point to start linear interpolation", OFFSET(interp_start_param),AV_OPT_TYPE_INT, {.i64=15}, 0, 255, V|F }, + {"interp_end", "point to end linear interpolation", OFFSET(interp_end_param), AV_OPT_TYPE_INT, {.i64=240}, 0, 255, V|F }, + {"scene", "scene change level", OFFSET(scene_score), AV_OPT_TYPE_DOUBLE, {.dbl=8.2}, 0, INT_MAX, V|F }, {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, INT_MAX, V|F, "flags" }, {"scene_change_detect", "enable scene change detection", 0, AV_OPT_TYPE_CONST, {.i64=FRAMERATE_FLAG_SCD}, INT_MIN, INT_MAX, V|F, "flags" }, @@ -101,25 +95,6 @@ static const AVOption framerate_options[] = { AVFILTER_DEFINE_CLASS(framerate); -static void next_source(AVFilterContext *ctx) -{ - FrameRateContext *s = ctx->priv; - int i; - - ff_dlog(ctx, "next_source()\n"); - - if (s->srce[s->last] && s->srce[s->last] != s->srce[s->last-1]) { - ff_dlog(ctx, "next_source() unlink %d\n", s->last); - av_frame_free(&s->srce[s->last]); - } - for (i = s->last; i > s->frst; i--) { - ff_dlog(ctx, "next_source() copy %d to %d\n", i - 1, i); - s->srce[i] = s->srce[i - 1]; - } - ff_dlog(ctx, "next_source() make %d null\n", s->frst); - s->srce[s->frst] = NULL; -} - static av_always_inline int64_t sad_8x8_16(const uint16_t *src1, ptrdiff_t stride1, const uint16_t *src2, ptrdiff_t stride2) { @@ -135,41 +110,35 @@ static av_always_inline int64_t sad_8x8_16(const uint16_t *src1, ptrdiff_t strid return sum; } -static double get_scene_score16(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next) +static int64_t scene_sad16(FrameRateContext *s, const uint16_t *p1, int p1_linesize, const uint16_t* p2, int p2_linesize, const int width, const int height) { - FrameRateContext *s = ctx->priv; - double ret = 0; - - ff_dlog(ctx, "get_scene_score16()\n"); - - if (crnt && - crnt->height == next->height && - crnt->width == next->width) { - int x, y; - int64_t sad; - double mafd, diff; - const uint16_t *p1 = (const uint16_t *)crnt->data[0]; - const uint16_t *p2 = (const uint16_t *)next->data[0]; - const int p1_linesize = crnt->linesize[0] / 2; - const int p2_linesize = next->linesize[0] / 2; - - ff_dlog(ctx, "get_scene_score16() process\n"); - - for (sad = y = 0; y < crnt->height; y += 8) { - for (x = 0; x < p1_linesize; x += 8) { - sad += sad_8x8_16(p1 + y * p1_linesize + x, - p1_linesize, - p2 + y * p2_linesize + x, - p2_linesize); - } + int64_t sad; + int x, y; + for (sad = y = 0; y < height - 7; y += 8) { + for (x = 0; x < width - 7; x += 8) { + sad += sad_8x8_16(p1 + y * p1_linesize + x, + p1_linesize, + p2 + y * p2_linesize + x, + p2_linesize); } - mafd = sad / (crnt->height * crnt->width * 3); - diff = fabs(mafd - s->prev_mafd); - ret = av_clipf(FFMIN(mafd, diff), 0, 100.0); - s->prev_mafd = mafd; } - ff_dlog(ctx, "get_scene_score16() result is:%f\n", ret); - return ret; + return sad; +} + +static int64_t scene_sad8(FrameRateContext *s, uint8_t *p1, int p1_linesize, uint8_t* p2, int p2_linesize, const int width, const int height) +{ + int64_t sad; + int x, y; + for (sad = y = 0; y < height - 7; y += 8) { + for (x = 0; x < width - 7; x += 8) { + sad += s->sad(p1 + y * p1_linesize + x, + p1_linesize, + p2 + y * p2_linesize + x, + p2_linesize); + } + } + emms_c(); + return sad; } static double get_scene_score(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next) @@ -179,358 +148,231 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next ff_dlog(ctx, "get_scene_score()\n"); - if (crnt && - crnt->height == next->height && + if (crnt->height == next->height && crnt->width == next->width) { - int x, y; int64_t sad; double mafd, diff; - uint8_t *p1 = crnt->data[0]; - uint8_t *p2 = next->data[0]; - const int p1_linesize = crnt->linesize[0]; - const int p2_linesize = next->linesize[0]; ff_dlog(ctx, "get_scene_score() process\n"); + if (s->bitdepth == 8) + sad = scene_sad8(s, crnt->data[0], crnt->linesize[0], next->data[0], next->linesize[0], crnt->width, crnt->height); + else + sad = scene_sad16(s, (const uint16_t*)crnt->data[0], crnt->linesize[0] / 2, (const uint16_t*)next->data[0], next->linesize[0] / 2, crnt->width, crnt->height); - for (sad = y = 0; y < crnt->height; y += 8) { - for (x = 0; x < p1_linesize; x += 8) { - sad += s->sad(p1 + y * p1_linesize + x, - p1_linesize, - p2 + y * p2_linesize + x, - p2_linesize); - } - } - emms_c(); - mafd = sad / (crnt->height * crnt->width * 3); + mafd = (double)sad * 100.0 / FFMAX(1, (crnt->height & ~7) * (crnt->width & ~7)) / (1 << s->bitdepth); diff = fabs(mafd - s->prev_mafd); ret = av_clipf(FFMIN(mafd, diff), 0, 100.0); s->prev_mafd = mafd; } - ff_dlog(ctx, "get_scene_score() result is:%f\n", ret); + ff_dlog(ctx, "get_scene_score() result is:%f\n", ret); return ret; } -static int blend_frames16(AVFilterContext *ctx, float interpolate, - AVFrame *copy_src1, AVFrame *copy_src2) +typedef struct ThreadData { + AVFrame *copy_src1, *copy_src2; + uint16_t src1_factor, src2_factor; +} ThreadData; + +static int filter_slice8(AVFilterContext *ctx, void *arg, int job, int nb_jobs) { FrameRateContext *s = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - double interpolate_scene_score = 0; + ThreadData *td = arg; + uint16_t src1_factor = td->src1_factor; + uint16_t src2_factor = td->src2_factor; + int plane, line, pixel; - if ((s->flags & FRAMERATE_FLAG_SCD) && copy_src2) { - interpolate_scene_score = get_scene_score16(ctx, copy_src1, copy_src2); - ff_dlog(ctx, "blend_frames16() interpolate scene score:%f\n", interpolate_scene_score); - } - // decide if the shot-change detection allows us to blend two frames - if (interpolate_scene_score < s->scene_score && copy_src2) { - uint16_t src2_factor = fabsf(interpolate) * (1 << (s->bitdepth - 8)); - uint16_t src1_factor = s->max - src2_factor; - const int half = s->max / 2; - const int uv = (s->max + 1) * half; - const int shift = s->bitdepth; - int plane, line, pixel; + for (plane = 0; plane < 4 && td->copy_src1->data[plane] && td->copy_src2->data[plane]; plane++) { + int cpy_line_width = s->line_size[plane]; + uint8_t *cpy_src1_data = td->copy_src1->data[plane]; + int cpy_src1_line_size = td->copy_src1->linesize[plane]; + uint8_t *cpy_src2_data = td->copy_src2->data[plane]; + int cpy_src2_line_size = td->copy_src2->linesize[plane]; + int cpy_src_h = (plane > 0 && plane < 3) ? (td->copy_src1->height >> s->vsub) : (td->copy_src1->height); + uint8_t *cpy_dst_data = s->work->data[plane]; + int cpy_dst_line_size = s->work->linesize[plane]; + const int start = (cpy_src_h * job ) / nb_jobs; + const int end = (cpy_src_h * (job+1)) / nb_jobs; + cpy_src1_data += start * cpy_src1_line_size; + cpy_src2_data += start * cpy_src2_line_size; + cpy_dst_data += start * cpy_dst_line_size; - // get work-space for output frame - s->work = ff_get_video_buffer(outlink, outlink->w, outlink->h); - if (!s->work) - return AVERROR(ENOMEM); - - av_frame_copy_props(s->work, s->srce[s->crnt]); - - ff_dlog(ctx, "blend_frames16() INTERPOLATE to create work frame\n"); - for (plane = 0; plane < 4 && copy_src1->data[plane] && copy_src2->data[plane]; plane++) { - int cpy_line_width = s->line_size[plane]; - const uint16_t *cpy_src1_data = (const uint16_t *)copy_src1->data[plane]; - int cpy_src1_line_size = copy_src1->linesize[plane] / 2; - const uint16_t *cpy_src2_data = (const uint16_t *)copy_src2->data[plane]; - int cpy_src2_line_size = copy_src2->linesize[plane] / 2; - int cpy_src_h = (plane > 0 && plane < 3) ? (copy_src1->height >> s->vsub) : (copy_src1->height); - uint16_t *cpy_dst_data = (uint16_t *)s->work->data[plane]; - int cpy_dst_line_size = s->work->linesize[plane] / 2; - - if (plane <1 || plane >2) { - // luma or alpha - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) - cpy_dst_data[pixel] = ((cpy_src1_data[pixel] * src1_factor) + (cpy_src2_data[pixel] * src2_factor) + half) >> shift; - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } else { - // chroma - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) { - cpy_dst_data[pixel] = (((cpy_src1_data[pixel] - half) * src1_factor) + ((cpy_src2_data[pixel] - half) * src2_factor) + uv) >> shift; - } - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; + if (plane <1 || plane >2) { + // luma or alpha + for (line = start; line < end; line++) { + for (pixel = 0; pixel < cpy_line_width; pixel++) { + // integer version of (src1 * src1_factor) + (src2 + src2_factor) + 0.5 + // 0.5 is for rounding + // 128 is the integer representation of 0.5 << 8 + cpy_dst_data[pixel] = ((cpy_src1_data[pixel] * src1_factor) + (cpy_src2_data[pixel] * src2_factor) + 128) >> 8; } + cpy_src1_data += cpy_src1_line_size; + cpy_src2_data += cpy_src2_line_size; + cpy_dst_data += cpy_dst_line_size; } - } - return 1; - } - return 0; -} - -static int blend_frames8(AVFilterContext *ctx, float interpolate, - AVFrame *copy_src1, AVFrame *copy_src2) -{ - FrameRateContext *s = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - double interpolate_scene_score = 0; - - if ((s->flags & FRAMERATE_FLAG_SCD) && copy_src2) { - interpolate_scene_score = get_scene_score(ctx, copy_src1, copy_src2); - ff_dlog(ctx, "blend_frames8() interpolate scene score:%f\n", interpolate_scene_score); - } - // decide if the shot-change detection allows us to blend two frames - if (interpolate_scene_score < s->scene_score && copy_src2) { - uint16_t src2_factor = fabsf(interpolate); - uint16_t src1_factor = 256 - src2_factor; - int plane, line, pixel; - - // get work-space for output frame - s->work = ff_get_video_buffer(outlink, outlink->w, outlink->h); - if (!s->work) - return AVERROR(ENOMEM); - - av_frame_copy_props(s->work, s->srce[s->crnt]); - - ff_dlog(ctx, "blend_frames8() INTERPOLATE to create work frame\n"); - for (plane = 0; plane < 4 && copy_src1->data[plane] && copy_src2->data[plane]; plane++) { - int cpy_line_width = s->line_size[plane]; - uint8_t *cpy_src1_data = copy_src1->data[plane]; - int cpy_src1_line_size = copy_src1->linesize[plane]; - uint8_t *cpy_src2_data = copy_src2->data[plane]; - int cpy_src2_line_size = copy_src2->linesize[plane]; - int cpy_src_h = (plane > 0 && plane < 3) ? (copy_src1->height >> s->vsub) : (copy_src1->height); - uint8_t *cpy_dst_data = s->work->data[plane]; - int cpy_dst_line_size = s->work->linesize[plane]; - if (plane <1 || plane >2) { - // luma or alpha - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) { - // integer version of (src1 * src1_factor) + (src2 + src2_factor) + 0.5 - // 0.5 is for rounding - // 128 is the integer representation of 0.5 << 8 - cpy_dst_data[pixel] = ((cpy_src1_data[pixel] * src1_factor) + (cpy_src2_data[pixel] * src2_factor) + 128) >> 8; - } - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } else { - // chroma - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) { - // as above - // because U and V are based around 128 we have to subtract 128 from the components. - // 32896 is the integer representation of 128.5 << 8 - cpy_dst_data[pixel] = (((cpy_src1_data[pixel] - 128) * src1_factor) + ((cpy_src2_data[pixel] - 128) * src2_factor) + 32896) >> 8; - } - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } - } - return 1; - } - return 0; -} - -static int process_work_frame(AVFilterContext *ctx, int stop) -{ - FrameRateContext *s = ctx->priv; - int64_t work_next_pts; - AVFrame *copy_src1; - float interpolate; - - ff_dlog(ctx, "process_work_frame()\n"); - - ff_dlog(ctx, "process_work_frame() pending_input_frames %d\n", s->pending_srce_frames); - - if (s->srce[s->prev]) ff_dlog(ctx, "process_work_frame() srce prev pts:%"PRId64"\n", s->srce[s->prev]->pts); - if (s->srce[s->crnt]) ff_dlog(ctx, "process_work_frame() srce crnt pts:%"PRId64"\n", s->srce[s->crnt]->pts); - if (s->srce[s->next]) ff_dlog(ctx, "process_work_frame() srce next pts:%"PRId64"\n", s->srce[s->next]->pts); - - if (!s->srce[s->crnt]) { - // the filter cannot do anything - ff_dlog(ctx, "process_work_frame() no current frame cached: move on to next frame, do not output a frame\n"); - next_source(ctx); - return 0; - } - - work_next_pts = s->pts + s->average_dest_pts_delta; - - ff_dlog(ctx, "process_work_frame() work crnt pts:%"PRId64"\n", s->pts); - ff_dlog(ctx, "process_work_frame() work next pts:%"PRId64"\n", work_next_pts); - if (s->srce[s->prev]) - ff_dlog(ctx, "process_work_frame() srce prev pts:%"PRId64" at dest time base:%u/%u\n", - s->srce_pts_dest[s->prev], s->dest_time_base.num, s->dest_time_base.den); - if (s->srce[s->crnt]) - ff_dlog(ctx, "process_work_frame() srce crnt pts:%"PRId64" at dest time base:%u/%u\n", - s->srce_pts_dest[s->crnt], s->dest_time_base.num, s->dest_time_base.den); - if (s->srce[s->next]) - ff_dlog(ctx, "process_work_frame() srce next pts:%"PRId64" at dest time base:%u/%u\n", - s->srce_pts_dest[s->next], s->dest_time_base.num, s->dest_time_base.den); - - av_assert0(s->srce[s->next]); - - // should filter be skipping input frame (output frame rate is lower than input frame rate) - if (!s->flush && s->pts >= s->srce_pts_dest[s->next]) { - ff_dlog(ctx, "process_work_frame() work crnt pts >= srce next pts: SKIP FRAME, move on to next frame, do not output a frame\n"); - next_source(ctx); - s->pending_srce_frames--; - return 0; - } - - // calculate interpolation - interpolate = ((s->pts - s->srce_pts_dest[s->crnt]) * 256.0 / s->average_srce_pts_dest_delta); - ff_dlog(ctx, "process_work_frame() interpolate:%f/256\n", interpolate); - copy_src1 = s->srce[s->crnt]; - if (interpolate > s->interp_end) { - ff_dlog(ctx, "process_work_frame() source is:NEXT\n"); - copy_src1 = s->srce[s->next]; - } - if (s->srce[s->prev] && interpolate < -s->interp_end) { - ff_dlog(ctx, "process_work_frame() source is:PREV\n"); - copy_src1 = s->srce[s->prev]; - } - - // decide whether to blend two frames - if ((interpolate >= s->interp_start && interpolate <= s->interp_end) || (interpolate <= -s->interp_start && interpolate >= -s->interp_end)) { - AVFrame *copy_src2; - - if (interpolate > 0) { - ff_dlog(ctx, "process_work_frame() interpolate source is:NEXT\n"); - copy_src2 = s->srce[s->next]; } else { - ff_dlog(ctx, "process_work_frame() interpolate source is:PREV\n"); - copy_src2 = s->srce[s->prev]; + // chroma + for (line = start; line < end; line++) { + for (pixel = 0; pixel < cpy_line_width; pixel++) { + // as above + // because U and V are based around 128 we have to subtract 128 from the components. + // 32896 is the integer representation of 128.5 << 8 + cpy_dst_data[pixel] = (((cpy_src1_data[pixel] - 128) * src1_factor) + ((cpy_src2_data[pixel] - 128) * src2_factor) + 32896) >> 8; + } + cpy_src1_data += cpy_src1_line_size; + cpy_src2_data += cpy_src2_line_size; + cpy_dst_data += cpy_dst_line_size; + } + } + } + + return 0; +} + +static int filter_slice16(AVFilterContext *ctx, void *arg, int job, int nb_jobs) +{ + FrameRateContext *s = ctx->priv; + ThreadData *td = arg; + uint16_t src1_factor = td->src1_factor; + uint16_t src2_factor = td->src2_factor; + const int half = s->max / 2; + const int uv = (s->max + 1) * half; + const int shift = s->bitdepth; + int plane, line, pixel; + + for (plane = 0; plane < 4 && td->copy_src1->data[plane] && td->copy_src2->data[plane]; plane++) { + int cpy_line_width = s->line_size[plane]; + const uint16_t *cpy_src1_data = (const uint16_t *)td->copy_src1->data[plane]; + int cpy_src1_line_size = td->copy_src1->linesize[plane] / 2; + const uint16_t *cpy_src2_data = (const uint16_t *)td->copy_src2->data[plane]; + int cpy_src2_line_size = td->copy_src2->linesize[plane] / 2; + int cpy_src_h = (plane > 0 && plane < 3) ? (td->copy_src1->height >> s->vsub) : (td->copy_src1->height); + uint16_t *cpy_dst_data = (uint16_t *)s->work->data[plane]; + int cpy_dst_line_size = s->work->linesize[plane] / 2; + const int start = (cpy_src_h * job ) / nb_jobs; + const int end = (cpy_src_h * (job+1)) / nb_jobs; + cpy_src1_data += start * cpy_src1_line_size; + cpy_src2_data += start * cpy_src2_line_size; + cpy_dst_data += start * cpy_dst_line_size; + + if (plane <1 || plane >2) { + // luma or alpha + for (line = start; line < end; line++) { + for (pixel = 0; pixel < cpy_line_width; pixel++) + cpy_dst_data[pixel] = ((cpy_src1_data[pixel] * src1_factor) + (cpy_src2_data[pixel] * src2_factor) + half) >> shift; + cpy_src1_data += cpy_src1_line_size; + cpy_src2_data += cpy_src2_line_size; + cpy_dst_data += cpy_dst_line_size; + } + } else { + // chroma + for (line = start; line < end; line++) { + for (pixel = 0; pixel < cpy_line_width; pixel++) { + cpy_dst_data[pixel] = (((cpy_src1_data[pixel] - half) * src1_factor) + ((cpy_src2_data[pixel] - half) * src2_factor) + uv) >> shift; + } + cpy_src1_data += cpy_src1_line_size; + cpy_src2_data += cpy_src2_line_size; + cpy_dst_data += cpy_dst_line_size; + } + } + } + + return 0; +} + +static int blend_frames(AVFilterContext *ctx, int interpolate) +{ + FrameRateContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + double interpolate_scene_score = 0; + + if ((s->flags & FRAMERATE_FLAG_SCD)) { + if (s->score >= 0.0) + interpolate_scene_score = s->score; + else + interpolate_scene_score = s->score = get_scene_score(ctx, s->f0, s->f1); + ff_dlog(ctx, "blend_frames() interpolate scene score:%f\n", interpolate_scene_score); + } + // decide if the shot-change detection allows us to blend two frames + if (interpolate_scene_score < s->scene_score) { + ThreadData td; + td.copy_src1 = s->f0; + td.copy_src2 = s->f1; + td.src2_factor = interpolate; + td.src1_factor = s->max - td.src2_factor; + + // get work-space for output frame + s->work = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!s->work) + return AVERROR(ENOMEM); + + av_frame_copy_props(s->work, s->f0); + + ff_dlog(ctx, "blend_frames() INTERPOLATE to create work frame\n"); + ctx->internal->execute(ctx, s->bitdepth == 8 ? filter_slice8 : filter_slice16, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + return 1; + } + return 0; +} + +static int process_work_frame(AVFilterContext *ctx) +{ + FrameRateContext *s = ctx->priv; + int64_t work_pts; + int interpolate; + int ret; + + if (!s->f1) + return 0; + if (!s->f0 && !s->flush) + return 0; + + work_pts = s->start_pts + av_rescale_q(s->n, av_inv_q(s->dest_frame_rate), s->dest_time_base); + + if (work_pts >= s->pts1 && !s->flush) + return 0; + + if (!s->f0) { + s->work = av_frame_clone(s->f1); + } else { + if (work_pts >= s->pts1 + s->delta && s->flush) + return 0; + + interpolate = av_rescale(work_pts - s->pts0, s->max, s->delta); + ff_dlog(ctx, "process_work_frame() interpolate:%d/%d\n", interpolate, s->max); + if (interpolate > s->interp_end) { + s->work = av_frame_clone(s->f1); + } else if (interpolate < s->interp_start) { + s->work = av_frame_clone(s->f0); + } else { + ret = blend_frames(ctx, interpolate); + if (ret < 0) + return ret; + if (ret == 0) + s->work = av_frame_clone(interpolate > (s->max >> 1) ? s->f1 : s->f0); } - if (s->blend_frames(ctx, interpolate, copy_src1, copy_src2)) - goto copy_done; - else - ff_dlog(ctx, "process_work_frame() CUT - DON'T INTERPOLATE\n"); } - ff_dlog(ctx, "process_work_frame() COPY to the work frame\n"); - // copy the frame we decided is our base source - s->work = av_frame_clone(copy_src1); if (!s->work) return AVERROR(ENOMEM); -copy_done: - s->work->pts = s->pts; - - // should filter be re-using input frame (output frame rate is higher than input frame rate) - if (!s->flush && (work_next_pts + s->average_dest_pts_delta) < (s->srce_pts_dest[s->crnt] + s->average_srce_pts_dest_delta)) { - ff_dlog(ctx, "process_work_frame() REPEAT FRAME\n"); - } else { - ff_dlog(ctx, "process_work_frame() CONSUME FRAME, move to next frame\n"); - s->pending_srce_frames--; - next_source(ctx); - } - ff_dlog(ctx, "process_work_frame() output a frame\n"); - s->dest_frame_num++; - if (stop) - s->pending_end_frame = 0; - s->last_dest_frame_pts = s->work->pts; + s->work->pts = work_pts; + s->n++; return 1; } -static void set_srce_frame_dest_pts(AVFilterContext *ctx) -{ - FrameRateContext *s = ctx->priv; - - ff_dlog(ctx, "set_srce_frame_output_pts()\n"); - - // scale the input pts from the timebase difference between input and output - if (s->srce[s->prev]) - s->srce_pts_dest[s->prev] = av_rescale_q(s->srce[s->prev]->pts, s->srce_time_base, s->dest_time_base); - if (s->srce[s->crnt]) - s->srce_pts_dest[s->crnt] = av_rescale_q(s->srce[s->crnt]->pts, s->srce_time_base, s->dest_time_base); - if (s->srce[s->next]) - s->srce_pts_dest[s->next] = av_rescale_q(s->srce[s->next]->pts, s->srce_time_base, s->dest_time_base); -} - -static void set_work_frame_pts(AVFilterContext *ctx) -{ - FrameRateContext *s = ctx->priv; - int64_t pts, average_srce_pts_delta = 0; - - ff_dlog(ctx, "set_work_frame_pts()\n"); - - av_assert0(s->srce[s->next]); - av_assert0(s->srce[s->crnt]); - - ff_dlog(ctx, "set_work_frame_pts() srce crnt pts:%"PRId64"\n", s->srce[s->crnt]->pts); - ff_dlog(ctx, "set_work_frame_pts() srce next pts:%"PRId64"\n", s->srce[s->next]->pts); - if (s->srce[s->prev]) - ff_dlog(ctx, "set_work_frame_pts() srce prev pts:%"PRId64"\n", s->srce[s->prev]->pts); - - average_srce_pts_delta = s->average_srce_pts_dest_delta; - ff_dlog(ctx, "set_work_frame_pts() initial average srce pts:%"PRId64"\n", average_srce_pts_delta); - - set_srce_frame_dest_pts(ctx); - - // calculate the PTS delta - if ((pts = (s->srce_pts_dest[s->next] - s->srce_pts_dest[s->crnt]))) { - average_srce_pts_delta = average_srce_pts_delta?((average_srce_pts_delta+pts)>>1):pts; - } else if (s->srce[s->prev] && (pts = (s->srce_pts_dest[s->crnt] - s->srce_pts_dest[s->prev]))) { - average_srce_pts_delta = average_srce_pts_delta?((average_srce_pts_delta+pts)>>1):pts; - } - - s->average_srce_pts_dest_delta = average_srce_pts_delta; - ff_dlog(ctx, "set_work_frame_pts() average srce pts:%"PRId64"\n", average_srce_pts_delta); - ff_dlog(ctx, "set_work_frame_pts() average srce pts:%"PRId64" at dest time base:%u/%u\n", - s->average_srce_pts_dest_delta, s->dest_time_base.num, s->dest_time_base.den); - - if (ctx->inputs[0] && !s->average_dest_pts_delta) { - int64_t d = av_q2d(av_inv_q(av_mul_q(s->dest_time_base, s->dest_frame_rate))); - s->average_dest_pts_delta = d; - ff_dlog(ctx, "set_work_frame_pts() average dest pts delta:%"PRId64"\n", s->average_dest_pts_delta); - } - - if (!s->dest_frame_num) { - s->pts = s->last_dest_frame_pts = s->srce_pts_dest[s->crnt]; - } else { - s->pts = s->last_dest_frame_pts + s->average_dest_pts_delta; - } - - ff_dlog(ctx, "set_work_frame_pts() calculated pts:%"PRId64" at dest time base:%u/%u\n", - s->pts, s->dest_time_base.num, s->dest_time_base.den); -} - static av_cold int init(AVFilterContext *ctx) { FrameRateContext *s = ctx->priv; - - s->dest_frame_num = 0; - - s->crnt = (N_SRCE)>>1; - s->last = N_SRCE - 1; - - s->next = s->crnt - 1; - s->prev = s->crnt + 1; - + s->start_pts = AV_NOPTS_VALUE; return 0; } static av_cold void uninit(AVFilterContext *ctx) { FrameRateContext *s = ctx->priv; - int i; - - for (i = s->frst; i < s->last; i++) { - if (s->srce[i] && (s->srce[i] != s->srce[i + 1])) - av_frame_free(&s->srce[i]); - } - av_frame_free(&s->srce[s->last]); + av_frame_free(&s->f0); + av_frame_free(&s->f1); } static int query_formats(AVFilterContext *ctx) @@ -568,6 +410,8 @@ static int config_input(AVFilterLink *inlink) s->bitdepth = pix_desc->comp[0].depth; s->vsub = pix_desc->log2_chroma_h; + s->interp_start = s->interp_start_param << (s->bitdepth - 8); + s->interp_end = s->interp_end_param << (s->bitdepth - 8); s->sad = av_pixelutils_get_sad_fn(3, 3, 2, s); // 8x8 both sources aligned if (!s->sad) @@ -575,10 +419,6 @@ static int config_input(AVFilterLink *inlink) s->srce_time_base = inlink->time_base; - if (s->bitdepth == 8) - s->blend_frames = blend_frames8; - else - s->blend_frames = blend_frames16; s->max = 1 << (s->bitdepth); return 0; @@ -589,28 +429,48 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) int ret; AVFilterContext *ctx = inlink->dst; FrameRateContext *s = ctx->priv; - - // we have one new frame - s->pending_srce_frames++; + int64_t pts; if (inpicref->interlaced_frame) av_log(ctx, AV_LOG_WARNING, "Interlaced frame found - the output will not be correct.\n"); - // store the pointer to the new frame - av_frame_free(&s->srce[s->frst]); - s->srce[s->frst] = inpicref; - - if (!s->pending_end_frame && s->srce[s->crnt]) { - set_work_frame_pts(ctx); - s->pending_end_frame = 1; - } else { - set_srce_frame_dest_pts(ctx); + if (inpicref->pts == AV_NOPTS_VALUE) { + av_log(ctx, AV_LOG_WARNING, "Ignoring frame without PTS.\n"); + return 0; } - ret = process_work_frame(ctx, 1); - if (ret < 0) - return ret; - return ret ? ff_filter_frame(ctx->outputs[0], s->work) : 0; + pts = av_rescale_q(inpicref->pts, s->srce_time_base, s->dest_time_base); + if (s->f1 && pts == s->pts1) { + av_log(ctx, AV_LOG_WARNING, "Ignoring frame with same PTS.\n"); + return 0; + } + + av_frame_free(&s->f0); + s->f0 = s->f1; + s->pts0 = s->pts1; + s->f1 = inpicref; + s->pts1 = pts; + s->delta = s->pts1 - s->pts0; + s->score = -1.0; + + if (s->delta < 0) { + av_log(ctx, AV_LOG_WARNING, "PTS discontinuity.\n"); + s->start_pts = s->pts1; + s->n = 0; + av_frame_free(&s->f0); + } + + if (s->start_pts == AV_NOPTS_VALUE) + s->start_pts = s->pts1; + + do { + ret = process_work_frame(ctx); + if (ret <= 0) + return ret; + ret = ff_filter_frame(ctx->outputs[0], s->work); + } while (ret >= 0); + + return ret; } static int config_output(AVFilterLink *outlink) @@ -662,50 +522,21 @@ static int request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; FrameRateContext *s = ctx->priv; - int ret, i; + int ret; ff_dlog(ctx, "request_frame()\n"); - // if there is no "next" frame AND we are not in flush then get one from our input filter - if (!s->srce[s->frst] && !s->flush) - goto request; - - ff_dlog(ctx, "request_frame() REPEAT or FLUSH\n"); - - if (s->pending_srce_frames <= 0) { - ff_dlog(ctx, "request_frame() nothing else to do, return:EOF\n"); - return AVERROR_EOF; - } - - // otherwise, make brand-new frame and pass to our output filter - ff_dlog(ctx, "request_frame() FLUSH\n"); - - // back fill at end of file when source has no more frames - for (i = s->last; i > s->frst; i--) { - if (!s->srce[i - 1] && s->srce[i]) { - ff_dlog(ctx, "request_frame() copy:%d to:%d\n", i, i - 1); - s->srce[i - 1] = s->srce[i]; - } - } - - set_work_frame_pts(ctx); - ret = process_work_frame(ctx, 0); - if (ret < 0) - return ret; - if (ret) - return ff_filter_frame(ctx->outputs[0], s->work); - -request: - ff_dlog(ctx, "request_frame() call source's request_frame()\n"); ret = ff_request_frame(ctx->inputs[0]); - if (ret < 0 && (ret != AVERROR_EOF)) { - ff_dlog(ctx, "request_frame() source's request_frame() returned error:%d\n", ret); - return ret; - } else if (ret == AVERROR_EOF) { + if (ret == AVERROR_EOF && s->f1 && !s->flush) { s->flush = 1; + ret = process_work_frame(ctx); + if (ret < 0) + return ret; + ret = ret ? ff_filter_frame(ctx->outputs[0], s->work) : AVERROR_EOF; } + ff_dlog(ctx, "request_frame() source's request_frame() returned:%d\n", ret); - return 0; + return ret; } static const AVFilterPad framerate_inputs[] = { @@ -738,4 +569,5 @@ AVFilter ff_vf_framerate = { .query_formats = query_formats, .inputs = framerate_inputs, .outputs = framerate_outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c index 36dbd421c..2aa1259c9 100644 --- a/libavfilter/vf_geq.c +++ b/libavfilter/vf_geq.c @@ -33,11 +33,17 @@ #include "libavutil/pixdesc.h" #include "internal.h" +static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL }; +enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB }; + typedef struct GEQContext { const AVClass *class; AVExpr *e[4]; ///< expressions for each plane char *expr_str[4+3]; ///< expression strings for each plane AVFrame *picref; ///< current input buffer + uint8_t *dst; ///< reference pointer to the 8bits output + uint16_t *dst16; ///< reference pointer to the 16bits output + double values[VAR_VARS_NB]; ///< expression values int hsub, vsub; ///< chroma subsampling int planes; ///< number of planes int is_rgb; @@ -107,9 +113,6 @@ static double cb(void *priv, double x, double y) { return getpix(priv, x, y, 1) static double cr(void *priv, double x, double y) { return getpix(priv, x, y, 2); } static double alpha(void *priv, double x, double y) { return getpix(priv, x, y, 3); } -static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL }; -enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB }; - static av_cold int geq_init(AVFilterContext *ctx) { GEQContext *geq = ctx->priv; @@ -226,8 +229,62 @@ static int geq_config_props(AVFilterLink *inlink) geq->hsub = desc->log2_chroma_w; geq->vsub = desc->log2_chroma_h; + geq->bps = desc->comp[0].depth; geq->planes = desc->nb_components; - geq->bps = desc->comp[0].depth; + return 0; +} + +typedef struct ThreadData { + int height; + int width; + int plane; + int linesize; +} ThreadData; + +static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + GEQContext *geq = ctx->priv; + ThreadData *td = arg; + const int height = td->height; + const int width = td->width; + const int plane = td->plane; + const int linesize = td->linesize; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + int x, y; + uint8_t *ptr; + uint16_t *ptr16; + + double values[VAR_VARS_NB]; + values[VAR_W] = geq->values[VAR_W]; + values[VAR_H] = geq->values[VAR_H]; + values[VAR_N] = geq->values[VAR_N]; + values[VAR_SW] = geq->values[VAR_SW]; + values[VAR_SH] = geq->values[VAR_SH]; + values[VAR_T] = geq->values[VAR_T]; + + if (geq->bps == 8) { + for (y = slice_start; y < slice_end; y++) { + ptr = geq->dst + linesize * y; + values[VAR_Y] = y; + + for (x = 0; x < width; x++) { + values[VAR_X] = x; + ptr[x] = av_expr_eval(geq->e[plane], values, geq); + } + ptr += linesize; + } + } + else { + for (y = slice_start; y < slice_end; y++) { + ptr16 = geq->dst16 + (linesize/2) * y; + values[VAR_Y] = y; + for (x = 0; x < width; x++) { + values[VAR_X] = x; + ptr16[x] = av_expr_eval(geq->e[plane], values, geq); + } + } + } return 0; } @@ -235,13 +292,14 @@ static int geq_config_props(AVFilterLink *inlink) static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in) { int plane; - GEQContext *geq = inlink->dst->priv; + AVFilterContext *ctx = inlink->dst; + const int nb_threads = ff_filter_get_nb_threads(ctx); + GEQContext *geq = ctx->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; AVFrame *out; - double values[VAR_VARS_NB] = { - [VAR_N] = inlink->frame_count_out, - [VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base), - }; + + geq->values[VAR_N] = inlink->frame_count_out, + geq->values[VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base), geq->picref = in; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); @@ -252,34 +310,25 @@ static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); for (plane = 0; plane < geq->planes && out->data[plane]; plane++) { - int x, y; - uint8_t *dst = out->data[plane]; - uint16_t *dst16 = (uint16_t*)out->data[plane]; + const int width = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->w, geq->hsub) : inlink->w; + const int height = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->h, geq->vsub) : inlink->h; const int linesize = out->linesize[plane]; - const int w = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->w, geq->hsub) : inlink->w; - const int h = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->h, geq->vsub) : inlink->h; + ThreadData td; - values[VAR_W] = w; - values[VAR_H] = h; - values[VAR_SW] = w / (double)inlink->w; - values[VAR_SH] = h / (double)inlink->h; + geq->dst = out->data[plane]; + geq->dst16 = (uint16_t*)out->data[plane]; - for (y = 0; y < h; y++) { - values[VAR_Y] = y; - if (geq->bps > 8) { - for (x = 0; x < w; x++) { - values[VAR_X] = x; - dst16[x] = av_expr_eval(geq->e[plane], values, geq); - } - dst16 += linesize / 2; - } else { - for (x = 0; x < w; x++) { - values[VAR_X] = x; - dst[x] = av_expr_eval(geq->e[plane], values, geq); - } - dst += linesize; - } - } + geq->values[VAR_W] = width; + geq->values[VAR_H] = height; + geq->values[VAR_SW] = width / (double)inlink->w; + geq->values[VAR_SH] = height / (double)inlink->h; + + td.width = width; + td.height = height; + td.plane = plane; + td.linesize = linesize; + + ctx->internal->execute(ctx, slice_geq_filter, &td, NULL, FFMIN(height, nb_threads)); } av_frame_free(&geq->picref); @@ -323,5 +372,5 @@ AVFilter ff_vf_geq = { .inputs = geq_inputs, .outputs = geq_outputs, .priv_class = &geq_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c index cf20c193f..b77afc77f 100644 --- a/libavfilter/vf_hflip.c +++ b/libavfilter/vf_hflip.c @@ -29,6 +29,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "formats.h" +#include "hflip.h" #include "internal.h" #include "video.h" #include "libavutil/pixdesc.h" @@ -36,13 +37,6 @@ #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" -typedef struct FlipContext { - const AVClass *class; - int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes - int planewidth[4]; ///< width of each plane - int planeheight[4]; ///< height of each plane -} FlipContext; - static const AVOption hflip_options[] = { { NULL } }; @@ -67,12 +61,77 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, pix_fmts); } +static void hflip_byte_c(const uint8_t *src, uint8_t *dst, int w) +{ + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + +static void hflip_short_c(const uint8_t *ssrc, uint8_t *ddst, int w) +{ + const uint16_t *src = (const uint16_t *)ssrc; + uint16_t *dst = (uint16_t *)ddst; + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + +static void hflip_dword_c(const uint8_t *ssrc, uint8_t *ddst, int w) +{ + const uint32_t *src = (const uint32_t *)ssrc; + uint32_t *dst = (uint32_t *)ddst; + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + +static void hflip_b24_c(const uint8_t *src, uint8_t *dst, int w) +{ + const uint8_t *in = src; + uint8_t *out = dst; + int j; + + for (j = 0; j < w; j++, out += 3, in -= 3) { + int32_t v = AV_RB24(in); + + AV_WB24(out, v); + } +} + +static void hflip_b48_c(const uint8_t *src, uint8_t *dst, int w) +{ + const uint8_t *in = src; + uint8_t *out = dst; + int j; + + for (j = 0; j < w; j++, out += 6, in -= 6) { + int64_t v = AV_RB48(in); + + AV_WB48(out, v); + } +} + +static void hflip_qword_c(const uint8_t *ssrc, uint8_t *ddst, int w) +{ + const uint64_t *src = (const uint64_t *)ssrc; + uint64_t *dst = (uint64_t *)ddst; + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + static int config_props(AVFilterLink *inlink) { FlipContext *s = inlink->dst->priv; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); const int hsub = pix_desc->log2_chroma_w; const int vsub = pix_desc->log2_chroma_h; + int nb_planes; av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc); s->planewidth[0] = s->planewidth[3] = inlink->w; @@ -80,6 +139,30 @@ static int config_props(AVFilterLink *inlink) s->planeheight[0] = s->planeheight[3] = inlink->h; s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, vsub); + nb_planes = av_pix_fmt_count_planes(inlink->format); + + return ff_hflip_init(s, s->max_step, nb_planes); +} + +int ff_hflip_init(FlipContext *s, int step[4], int nb_planes) +{ + int i; + + for (i = 0; i < nb_planes; i++) { + switch (step[i]) { + case 1: s->flip_line[i] = hflip_byte_c; break; + case 2: s->flip_line[i] = hflip_short_c; break; + case 3: s->flip_line[i] = hflip_b24_c; break; + case 4: s->flip_line[i] = hflip_dword_c; break; + case 6: s->flip_line[i] = hflip_b48_c; break; + case 8: s->flip_line[i] = hflip_qword_c; break; + default: + return AVERROR_BUG; + } + } + if (ARCH_X86) + ff_hflip_init_x86(s, step, nb_planes); + return 0; } @@ -94,7 +177,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) AVFrame *in = td->in; AVFrame *out = td->out; uint8_t *inrow, *outrow; - int i, j, plane, step; + int i, plane, step; for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { const int width = s->planewidth[plane]; @@ -107,45 +190,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) outrow = out->data[plane] + start * out->linesize[plane]; inrow = in ->data[plane] + start * in->linesize[plane] + (width - 1) * step; for (i = start; i < end; i++) { - switch (step) { - case 1: - for (j = 0; j < width; j++) - outrow[j] = inrow[-j]; - break; - - case 2: - { - uint16_t *outrow16 = (uint16_t *)outrow; - uint16_t * inrow16 = (uint16_t *) inrow; - for (j = 0; j < width; j++) - outrow16[j] = inrow16[-j]; - } - break; - - case 3: - { - uint8_t *in = inrow; - uint8_t *out = outrow; - for (j = 0; j < width; j++, out += 3, in -= 3) { - int32_t v = AV_RB24(in); - AV_WB24(out, v); - } - } - break; - - case 4: - { - uint32_t *outrow32 = (uint32_t *)outrow; - uint32_t * inrow32 = (uint32_t *) inrow; - for (j = 0; j < width; j++) - outrow32[j] = inrow32[-j]; - } - break; - - default: - for (j = 0; j < width; j++) - memcpy(outrow + j*step, inrow - j*step, step); - } + s->flip_line[plane](inrow, outrow, width); inrow += in ->linesize[plane]; outrow += out->linesize[plane]; diff --git a/libavfilter/vf_hwmap.c b/libavfilter/vf_hwmap.c index 8277241dc..d5fc3c46e 100644 --- a/libavfilter/vf_hwmap.c +++ b/libavfilter/vf_hwmap.c @@ -114,7 +114,8 @@ static int hwmap_config_output(AVFilterLink *outlink) err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, device, - inlink->hw_frames_ctx, 0); + inlink->hw_frames_ctx, + ctx->mode); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create derived " "frames context: %d.\n", err); diff --git a/libavfilter/vf_hysteresis.c b/libavfilter/vf_hysteresis.c index a788e1b9e..551b33f33 100644 --- a/libavfilter/vf_hysteresis.c +++ b/libavfilter/vf_hysteresis.c @@ -33,6 +33,7 @@ typedef struct HysteresisContext { const AVClass *class; + FFFrameSync fs; int planes; int threshold; @@ -40,7 +41,6 @@ typedef struct HysteresisContext { int width[4], height[4]; int nb_planes; int depth; - FFFrameSync fs; uint8_t *map; uint32_t *xy; @@ -58,8 +58,6 @@ static const AVOption hysteresis_options[] = { { NULL } }; -AVFILTER_DEFINE_CLASS(hysteresis); - static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { @@ -301,20 +299,13 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (base->w != alt->w || - base->h != alt->h || - base->sample_aspect_ratio.num != alt->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != alt->sample_aspect_ratio.den) { + if (base->w != alt->w || base->h != alt->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, base->w, base->h, - base->sample_aspect_ratio.num, - base->sample_aspect_ratio.den, ctx->input_pads[1].name, - alt->w, alt->h, - alt->sample_aspect_ratio.num, - alt->sample_aspect_ratio.den); + alt->w, alt->h); return AVERROR(EINVAL); } @@ -357,6 +348,8 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->xy); } +FRAMESYNC_DEFINE_CLASS(hysteresis, HysteresisContext, fs); + static const AVFilterPad hysteresis_inputs[] = { { .name = "base", @@ -382,6 +375,7 @@ static const AVFilterPad hysteresis_outputs[] = { AVFilter ff_vf_hysteresis = { .name = "hysteresis", .description = NULL_IF_CONFIG_SMALL("Grow first stream into second stream by connecting components."), + .preinit = hysteresis_framesync_preinit, .priv_size = sizeof(HysteresisContext), .uninit = uninit, .query_formats = query_formats, diff --git a/libavfilter/vf_interlace.c b/libavfilter/vf_interlace.c index 731069818..24c422ded 100644 --- a/libavfilter/vf_interlace.c +++ b/libavfilter/vf_interlace.c @@ -185,6 +185,25 @@ static av_cold void uninit(AVFilterContext *ctx) av_frame_free(&s->next); } +void ff_interlace_init(InterlaceContext *s, int depth) +{ + if (s->lowpass) { + if (s->lowpass == VLPF_LIN) { + if (depth > 8) + s->lowpass_line = lowpass_line_c_16; + else + s->lowpass_line = lowpass_line_c; + } else if (s->lowpass == VLPF_CMP) { + if (depth > 8) + s->lowpass_line = lowpass_line_complex_c_16; + else + s->lowpass_line = lowpass_line_complex_c; + } + if (ARCH_X86) + ff_interlace_init_x86(s, depth); + } +} + static int config_out_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -210,21 +229,7 @@ static int config_out_props(AVFilterLink *outlink) outlink->frame_rate.den *= 2; s->csp = av_pix_fmt_desc_get(outlink->format); - if (s->lowpass) { - if (s->lowpass == VLPF_LIN) { - if (s->csp->comp[0].depth > 8) - s->lowpass_line = lowpass_line_c_16; - else - s->lowpass_line = lowpass_line_c; - } else if (s->lowpass == VLPF_CMP) { - if (s->csp->comp[0].depth > 8) - s->lowpass_line = lowpass_line_complex_c_16; - else - s->lowpass_line = lowpass_line_complex_c; - } - if (ARCH_X86) - ff_interlace_init_x86(s); - } + ff_interlace_init(s, s->csp->comp[0].depth); av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n", s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without"); diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c index 2c3a9f334..dfe474c40 100644 --- a/libavfilter/vf_libvmaf.c +++ b/libavfilter/vf_libvmaf.c @@ -40,7 +40,6 @@ typedef struct LIBVMAFContext { const AVClass *class; FFFrameSync fs; const AVPixFmtDescriptor *desc; - char *format; int width; int height; double vmaf_score; @@ -62,6 +61,7 @@ typedef struct LIBVMAFContext { int ssim; int ms_ssim; char *pool; + int error; } LIBVMAFContext; #define OFFSET(x) offsetof(LIBVMAFContext, x) @@ -149,6 +149,7 @@ static void compute_vmaf_score(LIBVMAFContext *s) { int (*read_frame)(float *ref_data, float *main_data, float *temp_data, int stride, void *ctx); + char *format; if (s->desc->comp[0].depth <= 8) { read_frame = read_frame_8bit; @@ -156,48 +157,65 @@ static void compute_vmaf_score(LIBVMAFContext *s) read_frame = read_frame_10bit; } - s->vmaf_score = compute_vmaf(s->format, s->width, s->height, read_frame, s, - s->model_path, s->log_path, s->log_fmt, 0, 0, - s->enable_transform, s->phone_model, s->psnr, - s->ssim, s->ms_ssim, s->pool); + format = (char *) s->desc->name; + + s->error = compute_vmaf(&s->vmaf_score, format, s->width, s->height, + read_frame, s, s->model_path, s->log_path, + s->log_fmt, 0, 0, s->enable_transform, + s->phone_model, s->psnr, s->ssim, + s->ms_ssim, s->pool); } static void *call_vmaf(void *ctx) { LIBVMAFContext *s = (LIBVMAFContext *) ctx; compute_vmaf_score(s); - av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n",s->vmaf_score); + if (!s->error) { + av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n",s->vmaf_score); + } else { + pthread_mutex_lock(&s->lock); + pthread_cond_signal(&s->cond); + pthread_mutex_unlock(&s->lock); + } pthread_exit(NULL); + return NULL; } static int do_vmaf(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; LIBVMAFContext *s = ctx->priv; - AVFrame *main, *ref; + AVFrame *master, *ref; int ret; - ret = ff_framesync_dualinput_get(fs, &main, &ref); + ret = ff_framesync_dualinput_get(fs, &master, &ref); if (ret < 0) return ret; if (!ref) - return ff_filter_frame(ctx->outputs[0], main); + return ff_filter_frame(ctx->outputs[0], master); pthread_mutex_lock(&s->lock); - while (s->frame_set != 0) { + while (s->frame_set && !s->error) { pthread_cond_wait(&s->cond, &s->lock); } + if (s->error) { + av_log(ctx, AV_LOG_ERROR, + "libvmaf encountered an error, check log for details\n"); + pthread_mutex_unlock(&s->lock); + return AVERROR(EINVAL); + } + av_frame_ref(s->gref, ref); - av_frame_ref(s->gmain, main); + av_frame_ref(s->gmain, master); s->frame_set = 1; pthread_cond_signal(&s->cond); pthread_mutex_unlock(&s->lock); - return ff_filter_frame(ctx->outputs[0], main); + return ff_filter_frame(ctx->outputs[0], master); } static av_cold int init(AVFilterContext *ctx) @@ -206,6 +224,7 @@ static av_cold int init(AVFilterContext *ctx) s->gref = av_frame_alloc(); s->gmain = av_frame_alloc(); + s->error = 0; pthread_mutex_init(&s->lock, NULL); pthread_cond_init (&s->cond, NULL); @@ -258,7 +277,6 @@ static int config_input_ref(AVFilterLink *inlink) return 0; } - static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c index 11c039ead..26f2945c8 100644 --- a/libavfilter/vf_lut.c +++ b/libavfilter/vf_lut.c @@ -135,9 +135,13 @@ static av_cold void uninit(AVFilterContext *ctx) AV_PIX_FMT_GBRP16LE, AV_PIX_FMT_GBRAP12LE, \ AV_PIX_FMT_GBRAP16LE +#define GRAY_FORMATS \ + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9LE, AV_PIX_FMT_GRAY10LE, \ + AV_PIX_FMT_GRAY12LE, AV_PIX_FMT_GRAY16LE + static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE }; static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE }; -static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE }; +static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, GRAY_FORMATS, AV_PIX_FMT_NONE }; static int query_formats(AVFilterContext *ctx) { diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c index 585d121ca..1385cba9b 100644 --- a/libavfilter/vf_lut2.c +++ b/libavfilter/vf_lut2.c @@ -304,20 +304,13 @@ static int lut2_config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (srcx->w != srcy->w || - srcx->h != srcy->h || - srcx->sample_aspect_ratio.num != srcy->sample_aspect_ratio.num || - srcx->sample_aspect_ratio.den != srcy->sample_aspect_ratio.den) { + if (srcx->w != srcy->w || srcx->h != srcy->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, srcx->w, srcx->h, - srcx->sample_aspect_ratio.num, - srcx->sample_aspect_ratio.den, ctx->input_pads[1].name, - srcy->w, srcy->h, - srcy->sample_aspect_ratio.num, - srcy->sample_aspect_ratio.den); + srcy->w, srcy->h); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_maskedclamp.c b/libavfilter/vf_maskedclamp.c index 67a979f8c..9812e0853 100644 --- a/libavfilter/vf_maskedclamp.c +++ b/libavfilter/vf_maskedclamp.c @@ -235,27 +235,15 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (base->w != dark->w || - base->h != dark->h || - base->sample_aspect_ratio.num != dark->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != dark->sample_aspect_ratio.den || - base->w != bright->w || - base->h != bright->h || - base->sample_aspect_ratio.num != bright->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != bright->sample_aspect_ratio.den) { + if (base->w != dark->w || base->h != dark->h || + base->w != bright->w || base->h != bright->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d) " - "and/or third input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (%dx%d) " + "and/or third input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, base->w, base->h, - base->sample_aspect_ratio.num, - base->sample_aspect_ratio.den, ctx->input_pads[1].name, dark->w, dark->h, - dark->sample_aspect_ratio.num, - dark->sample_aspect_ratio.den, - ctx->input_pads[2].name, bright->w, bright->h, - bright->sample_aspect_ratio.num, - bright->sample_aspect_ratio.den); + ctx->input_pads[2].name, bright->w, bright->h); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_maskedmerge.c b/libavfilter/vf_maskedmerge.c index d31b92659..86559abda 100644 --- a/libavfilter/vf_maskedmerge.c +++ b/libavfilter/vf_maskedmerge.c @@ -199,27 +199,15 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (base->w != overlay->w || - base->h != overlay->h || - base->sample_aspect_ratio.num != overlay->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != overlay->sample_aspect_ratio.den || - base->w != mask->w || - base->h != mask->h || - base->sample_aspect_ratio.num != mask->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != mask->sample_aspect_ratio.den) { + if (base->w != overlay->w || base->h != overlay->h || + base->w != mask->w || base->h != mask->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d) " - "and/or third input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d) " + "and/or third input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, base->w, base->h, - base->sample_aspect_ratio.num, - base->sample_aspect_ratio.den, ctx->input_pads[1].name, overlay->w, overlay->h, - overlay->sample_aspect_ratio.num, - overlay->sample_aspect_ratio.den, - ctx->input_pads[2].name, mask->w, mask->h, - mask->sample_aspect_ratio.num, - mask->sample_aspect_ratio.den); + ctx->input_pads[2].name, mask->w, mask->h); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c index 6c5c26400..d53431593 100644 --- a/libavfilter/vf_minterpolate.c +++ b/libavfilter/vf_minterpolate.c @@ -145,12 +145,18 @@ typedef struct Block { struct Block *subs; } Block; -typedef struct Pixel { +typedef struct PixelMVS { int16_t mvs[NB_PIXEL_MVS][2]; +} PixelMVS; + +typedef struct PixelWeights { uint32_t weights[NB_PIXEL_MVS]; +} PixelWeights; + +typedef struct PixelRefs { int8_t refs[NB_PIXEL_MVS]; int nb; -} Pixel; +} PixelRefs; typedef struct Frame { AVFrame *avf; @@ -172,7 +178,9 @@ typedef struct MIContext { Frame frames[NB_FRAMES]; Cluster clusters[NB_CLUSTERS]; Block *int_blocks; - Pixel *pixels; + PixelMVS *pixel_mvs; + PixelWeights *pixel_weights; + PixelRefs *pixel_refs; int (*mv_table[3])[2][2]; int64_t out_pts; int b_width, b_height, b_count; @@ -331,7 +339,7 @@ static int config_input(AVFilterLink *inlink) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); const int height = inlink->h; const int width = inlink->w; - int i; + int i, ret = 0; mi_ctx->log2_chroma_h = desc->log2_chroma_h; mi_ctx->log2_chroma_w = desc->log2_chroma_w; @@ -353,8 +361,13 @@ static int config_input(AVFilterLink *inlink) } if (mi_ctx->mi_mode == MI_MODE_MCI) { - if (!(mi_ctx->pixels = av_mallocz_array(width * height, sizeof(Pixel)))) - return AVERROR(ENOMEM); + mi_ctx->pixel_mvs = av_mallocz_array(width * height, sizeof(PixelMVS)); + mi_ctx->pixel_weights = av_mallocz_array(width * height, sizeof(PixelWeights)); + mi_ctx->pixel_refs = av_mallocz_array(width * height, sizeof(PixelRefs)); + if (!mi_ctx->pixel_mvs || !mi_ctx->pixel_weights || !mi_ctx->pixel_refs) { + ret = AVERROR(ENOMEM); + goto fail; + } if (mi_ctx->me_mode == ME_MODE_BILAT) if (!(mi_ctx->int_blocks = av_mallocz_array(mi_ctx->b_count, sizeof(Block)))) @@ -383,6 +396,13 @@ static int config_input(AVFilterLink *inlink) me_ctx->get_cost = &get_sbad_ob; return 0; +fail: + for (i = 0; i < NB_FRAMES; i++) + av_freep(&mi_ctx->frames[i].blocks); + av_freep(&mi_ctx->pixel_mvs); + av_freep(&mi_ctx->pixel_weights); + av_freep(&mi_ctx->pixel_refs); + return ret; } static int config_output(AVFilterLink *outlink) @@ -833,18 +853,18 @@ static int detect_scene_change(MIContext *mi_ctx) #define ADD_PIXELS(b_weight, mv_x, mv_y)\ do {\ - if (!b_weight || pixel->nb + 1 >= NB_PIXEL_MVS)\ + if (!b_weight || pixel_refs->nb + 1 >= NB_PIXEL_MVS)\ continue;\ - pixel->refs[pixel->nb] = 1;\ - pixel->weights[pixel->nb] = b_weight * (ALPHA_MAX - alpha);\ - pixel->mvs[pixel->nb][0] = av_clip((mv_x * alpha) / ALPHA_MAX, x_min, x_max);\ - pixel->mvs[pixel->nb][1] = av_clip((mv_y * alpha) / ALPHA_MAX, y_min, y_max);\ - pixel->nb++;\ - pixel->refs[pixel->nb] = 2;\ - pixel->weights[pixel->nb] = b_weight * alpha;\ - pixel->mvs[pixel->nb][0] = av_clip(-mv_x * (ALPHA_MAX - alpha) / ALPHA_MAX, x_min, x_max);\ - pixel->mvs[pixel->nb][1] = av_clip(-mv_y * (ALPHA_MAX - alpha) / ALPHA_MAX, y_min, y_max);\ - pixel->nb++;\ + pixel_refs->refs[pixel_refs->nb] = 1;\ + pixel_weights->weights[pixel_refs->nb] = b_weight * (ALPHA_MAX - alpha);\ + pixel_mvs->mvs[pixel_refs->nb][0] = av_clip((mv_x * alpha) / ALPHA_MAX, x_min, x_max);\ + pixel_mvs->mvs[pixel_refs->nb][1] = av_clip((mv_y * alpha) / ALPHA_MAX, y_min, y_max);\ + pixel_refs->nb++;\ + pixel_refs->refs[pixel_refs->nb] = 2;\ + pixel_weights->weights[pixel_refs->nb] = b_weight * alpha;\ + pixel_mvs->mvs[pixel_refs->nb][0] = av_clip(-mv_x * (ALPHA_MAX - alpha) / ALPHA_MAX, x_min, x_max);\ + pixel_mvs->mvs[pixel_refs->nb][1] = av_clip(-mv_y * (ALPHA_MAX - alpha) / ALPHA_MAX, y_min, y_max);\ + pixel_refs->nb++;\ } while(0) static void bidirectional_obmc(MIContext *mi_ctx, int alpha) @@ -856,7 +876,7 @@ static void bidirectional_obmc(MIContext *mi_ctx, int alpha) for (y = 0; y < height; y++) for (x = 0; x < width; x++) - mi_ctx->pixels[x + y * width].nb = 0; + mi_ctx->pixel_refs[x + y * width].nb = 0; for (dir = 0; dir < 2; dir++) for (mb_y = 0; mb_y < mi_ctx->b_height; mb_y++) @@ -887,7 +907,9 @@ static void bidirectional_obmc(MIContext *mi_ctx, int alpha) int x_min = -x; int x_max = width - x - 1; int obmc_weight = obmc_tab_linear[4 - mi_ctx->log2_mb_size][(x - start_x) + ((y - start_y) << (mi_ctx->log2_mb_size + 1))]; - Pixel *pixel = &mi_ctx->pixels[x + y * width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * width]; ADD_PIXELS(obmc_weight, mv_x, mv_y); } @@ -909,36 +931,38 @@ static void set_frame_data(MIContext *mi_ctx, int alpha, AVFrame *avf_out) int x_mv, y_mv; int weight_sum = 0; int i, val = 0; - Pixel *pixel = &mi_ctx->pixels[x + y * avf_out->width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * avf_out->width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * avf_out->width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * avf_out->width]; - for (i = 0; i < pixel->nb; i++) - weight_sum += pixel->weights[i]; + for (i = 0; i < pixel_refs->nb; i++) + weight_sum += pixel_weights->weights[i]; - if (!weight_sum || !pixel->nb) { - pixel->weights[0] = ALPHA_MAX - alpha; - pixel->refs[0] = 1; - pixel->mvs[0][0] = 0; - pixel->mvs[0][1] = 0; - pixel->weights[1] = alpha; - pixel->refs[1] = 2; - pixel->mvs[1][0] = 0; - pixel->mvs[1][1] = 0; - pixel->nb = 2; + if (!weight_sum || !pixel_refs->nb) { + pixel_weights->weights[0] = ALPHA_MAX - alpha; + pixel_refs->refs[0] = 1; + pixel_mvs->mvs[0][0] = 0; + pixel_mvs->mvs[0][1] = 0; + pixel_weights->weights[1] = alpha; + pixel_refs->refs[1] = 2; + pixel_mvs->mvs[1][0] = 0; + pixel_mvs->mvs[1][1] = 0; + pixel_refs->nb = 2; weight_sum = ALPHA_MAX; } - for (i = 0; i < pixel->nb; i++) { - Frame *frame = &mi_ctx->frames[pixel->refs[i]]; + for (i = 0; i < pixel_refs->nb; i++) { + Frame *frame = &mi_ctx->frames[pixel_refs->refs[i]]; if (chroma) { - x_mv = (x >> mi_ctx->log2_chroma_w) + pixel->mvs[i][0] / (1 << mi_ctx->log2_chroma_w); - y_mv = (y >> mi_ctx->log2_chroma_h) + pixel->mvs[i][1] / (1 << mi_ctx->log2_chroma_h); + x_mv = (x >> mi_ctx->log2_chroma_w) + pixel_mvs->mvs[i][0] / (1 << mi_ctx->log2_chroma_w); + y_mv = (y >> mi_ctx->log2_chroma_h) + pixel_mvs->mvs[i][1] / (1 << mi_ctx->log2_chroma_h); } else { - x_mv = x + pixel->mvs[i][0]; - y_mv = y + pixel->mvs[i][1]; + x_mv = x + pixel_mvs->mvs[i][0]; + y_mv = y + pixel_mvs->mvs[i][1]; } - val += pixel->weights[i] * frame->avf->data[plane][x_mv + y_mv * frame->avf->linesize[plane]]; + val += pixel_weights->weights[i] * frame->avf->data[plane][x_mv + y_mv * frame->avf->linesize[plane]]; } val = ROUNDED_DIV(val, weight_sum); @@ -979,7 +1003,9 @@ static void var_size_bmc(MIContext *mi_ctx, Block *block, int x_mb, int y_mb, in for (x = start_x; x < end_x; x++) { int x_min = -x; int x_max = width - x - 1; - Pixel *pixel = &mi_ctx->pixels[x + y * width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * width]; ADD_PIXELS(PX_WEIGHT_MAX, mv_x, mv_y); } @@ -1028,7 +1054,9 @@ static void bilateral_obmc(MIContext *mi_ctx, Block *block, int mb_x, int mb_y, int x_min = -x; int x_max = width - x - 1; int obmc_weight = obmc_tab_linear[4 - mi_ctx->log2_mb_size][(x - start_x) + ((y - start_y) << (mi_ctx->log2_mb_size + 1))]; - Pixel *pixel = &mi_ctx->pixels[x + y * width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * width]; if (mi_ctx->mc_mode == MC_MODE_AOBMC) { nb_x = (((x - start_x) >> (mi_ctx->log2_mb_size - 1)) * 2 - 3) / 2; @@ -1112,7 +1140,7 @@ static void interpolate(AVFilterLink *inlink, AVFrame *avf_out) for (y = 0; y < mi_ctx->frames[0].avf->height; y++) for (x = 0; x < mi_ctx->frames[0].avf->width; x++) - mi_ctx->pixels[x + y * mi_ctx->frames[0].avf->width].nb = 0; + mi_ctx->pixel_refs[x + y * mi_ctx->frames[0].avf->width].nb = 0; for (mb_y = 0; mb_y < mi_ctx->b_height; mb_y++) for (mb_x = 0; mb_x < mi_ctx->b_width; mb_x++) { @@ -1195,7 +1223,9 @@ static av_cold void uninit(AVFilterContext *ctx) MIContext *mi_ctx = ctx->priv; int i, m; - av_freep(&mi_ctx->pixels); + av_freep(&mi_ctx->pixel_mvs); + av_freep(&mi_ctx->pixel_weights); + av_freep(&mi_ctx->pixel_refs); if (mi_ctx->int_blocks) for (m = 0; m < mi_ctx->b_count; m++) free_blocks(&mi_ctx->int_blocks[m], 0); diff --git a/libavfilter/vf_mix.c b/libavfilter/vf_mix.c new file mode 100644 index 000000000..261ab066e --- /dev/null +++ b/libavfilter/vf_mix.c @@ -0,0 +1,283 @@ +/* + * 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 "libavutil/avstring.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "framesync.h" +#include "video.h" + +typedef struct MixContext { + const AVClass *class; + const AVPixFmtDescriptor *desc; + char *weights_str; + int nb_inputs; + int duration; + float *weights; + float wfactor; + + int depth; + int nb_planes; + int linesize[4]; + int height[4]; + + AVFrame **frames; + FFFrameSync fs; +} MixContext; + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *pix_fmts = NULL; + int fmt, ret; + + for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || + desc->flags & AV_PIX_FMT_FLAG_HWACCEL || + desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) && + (ret = ff_add_format(&pix_fmts, fmt)) < 0) + return ret; + } + + return ff_set_common_formats(ctx, pix_fmts); +} + +static av_cold int init(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + char *p, *arg, *saveptr = NULL; + int i, ret; + + s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); + if (!s->frames) + return AVERROR(ENOMEM); + + s->weights = av_calloc(s->nb_inputs, sizeof(*s->weights)); + if (!s->weights) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_inputs; i++) { + AVFilterPad pad = { 0 }; + + pad.type = AVMEDIA_TYPE_VIDEO; + pad.name = av_asprintf("input%d", i); + if (!pad.name) + return AVERROR(ENOMEM); + + if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } + } + + p = s->weights_str; + for (i = 0; i < s->nb_inputs; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + sscanf(arg, "%f", &s->weights[i]); + s->wfactor += s->weights[i]; + } + s->wfactor = 1 / s->wfactor; + + return 0; +} + +static int process_frame(FFFrameSync *fs) +{ + AVFilterContext *ctx = fs->parent; + AVFilterLink *outlink = ctx->outputs[0]; + MixContext *s = fs->opaque; + AVFrame **in = s->frames; + AVFrame *out; + int i, p, ret, x, y; + + for (i = 0; i < s->nb_inputs; i++) { + if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], 0)) < 0) + return ret; + } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); + + if (s->depth <= 8) { + for (p = 0; p < s->nb_planes; p++) { + uint8_t *dst = out->data[p]; + + for (y = 0; y < s->height[p]; y++) { + for (x = 0; x < s->linesize[p]; x++) { + int val = 0; + + for (i = 0; i < s->nb_inputs; i++) { + uint8_t src = in[i]->data[p][y * s->linesize[p] + x]; + + val += src * s->weights[i]; + } + + dst[x] = val * s->wfactor; + } + + dst += out->linesize[p]; + } + } + } else { + for (p = 0; p < s->nb_planes; p++) { + uint16_t *dst = (uint16_t *)out->data[p]; + + for (y = 0; y < s->height[p]; y++) { + for (x = 0; x < s->linesize[p]; x++) { + int val = 0; + + for (i = 0; i < s->nb_inputs; i++) { + uint16_t src = AV_RN16(in[i]->data[p] + y * s->linesize[p] + x * 2); + + val += src * s->weights[i]; + } + + dst[x] = val * s->wfactor; + } + + dst += out->linesize[p] / 2; + } + } + } + + return ff_filter_frame(outlink, out); +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + MixContext *s = ctx->priv; + AVRational time_base = ctx->inputs[0]->time_base; + AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVFilterLink *inlink = ctx->inputs[0]; + int height = ctx->inputs[0]->h; + int width = ctx->inputs[0]->w; + FFFrameSyncIn *in; + int i, ret; + + for (i = 1; i < s->nb_inputs; i++) { + if (ctx->inputs[i]->h != height || ctx->inputs[i]->w != width) { + av_log(ctx, AV_LOG_ERROR, "Input %d size (%dx%d) does not match input %d size (%dx%d).\n", i, ctx->inputs[i]->w, ctx->inputs[i]->h, 0, width, height); + return AVERROR(EINVAL); + } + } + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + + outlink->w = width; + outlink->h = height; + outlink->time_base = time_base; + outlink->frame_rate = frame_rate; + + if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) + return ret; + + in = s->fs.in; + s->fs.opaque = s; + s->fs.on_event = process_frame; + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + + for (i = 0; i < s->nb_inputs; i++) { + AVFilterLink *inlink = ctx->inputs[i]; + + in[i].time_base = inlink->time_base; + in[i].sync = 1; + in[i].before = EXT_STOP; + in[i].after = (s->duration == 1 || (s->duration == 2 && i == 0)) ? EXT_STOP : EXT_INFINITY; + } + + return ff_framesync_configure(&s->fs); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + int i; + + ff_framesync_uninit(&s->fs); + av_freep(&s->frames); + av_freep(&s->weights); + + for (i = 0; i < ctx->nb_inputs; i++) + av_freep(&ctx->input_pads[i].name); +} + +static int activate(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + return ff_framesync_activate(&s->fs); +} + +#define OFFSET(x) offsetof(MixContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption mix_options[] = { + { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=2}, 2, INT_MAX, .flags = FLAGS }, + { "weights", "set weight for each input", OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, .flags = FLAGS }, + { "duration", "how to determine end of stream", OFFSET(duration), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, .flags = FLAGS, "duration" }, + { "longest", "Duration of longest input", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "duration" }, + { "shortest", "Duration of shortest input", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "duration" }, + { "first", "Duration of first input", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "duration" }, + { NULL }, +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(mix); + +AVFilter ff_vf_mix = { + .name = "mix", + .description = NULL_IF_CONFIG_SMALL("Mix video inputs."), + .priv_size = sizeof(MixContext), + .priv_class = &mix_class, + .query_formats = query_formats, + .outputs = outputs, + .init = init, + .uninit = uninit, + .activate = activate, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, +}; diff --git a/libavfilter/vf_normalize.c b/libavfilter/vf_normalize.c new file mode 100644 index 000000000..5c1fe98c6 --- /dev/null +++ b/libavfilter/vf_normalize.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2017 Richard Ling + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Normalize RGB video (aka histogram stretching, contrast stretching). + * See: https://en.wikipedia.org/wiki/Normalization_(image_processing) + * + * For each channel of each frame, the filter computes the input range and maps + * it linearly to the user-specified output range. The output range defaults + * to the full dynamic range from pure black to pure white. + * + * Naively maximising the dynamic range of each frame of video in isolation + * may cause flickering (rapid changes in brightness of static objects in the + * scene) when small dark or bright objects enter or leave the scene. This + * filter can apply temporal smoothing to the input range to reduce flickering. + * Temporal smoothing is similar to the auto-exposure (automatic gain control) + * on a video camera, which performs the same function; and, like a video + * camera, it may cause a period of over- or under-exposure of the video. + * + * The filter can normalize the R,G,B channels independently, which may cause + * color shifting, or link them together as a single channel, which prevents + * color shifting. More precisely, linked normalization preserves hue (as it's + * defined in HSV/HSL color spaces) while independent normalization does not. + * Independent normalization can be used to remove color casts, such as the + * blue cast from underwater video, restoring more natural colors. The filter + * can also combine independent and linked normalization in any ratio. + * + * Finally the overall strength of the filter can be adjusted, from no effect + * to full normalization. + * + * The 5 AVOptions are: + * blackpt, Colors which define the output range. The minimum input value + * whitept is mapped to the blackpt. The maximum input value is mapped to + * the whitept. The defaults are black and white respectively. + * Specifying white for blackpt and black for whitept will give + * color-inverted, normalized video. Shades of grey can be used + * to reduce the dynamic range (contrast). Specifying saturated + * colors here can create some interesting effects. + * + * smoothing The amount of temporal smoothing, expressed in frames (>=0). + * the minimum and maximum input values of each channel are + * smoothed using a rolling average over the current frame and + * that many previous frames of video. Defaults to 0 (no temporal + * smoothing). + * + * independence + * Controls the ratio of independent (color shifting) channel + * normalization to linked (color preserving) normalization. 0.0 + * is fully linked, 1.0 is fully independent. Defaults to fully + * independent. + * + * strength Overall strength of the filter. 1.0 is full strength. 0.0 is + * a rather expensive no-op. Values in between can give a gentle + * boost to low-contrast video without creating an artificial + * over-processed look. The default is full strength. + */ + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct NormalizeContext { + const AVClass *class; + + // Storage for the corresponding AVOptions + uint8_t blackpt[4]; + uint8_t whitept[4]; + int smoothing; + float independence; + float strength; + + int co[4]; // Offsets to R,G,B,A bytes respectively in each pixel + int num_components; // Number of components in the pixel format + int history_len; // Number of frames to average; based on smoothing factor + int frame_num; // Increments on each frame, starting from 0. + + // Per-extremum, per-channel history, for temporal smoothing. + struct { + uint8_t *history; // History entries. + uint32_t history_sum; // Sum of history entries. + } min[3], max[3]; // Min and max for each channel in {R,G,B}. + uint8_t *history_mem; // Single allocation for above history entries + +} NormalizeContext; + +#define OFFSET(x) offsetof(NormalizeContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption normalize_options[] = { + { "blackpt", "output color to which darkest input color is mapped", OFFSET(blackpt), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "whitept", "output color to which brightest input color is mapped", OFFSET(whitept), AV_OPT_TYPE_COLOR, { .str = "white" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "smoothing", "amount of temporal smoothing of the input range, to reduce flicker", OFFSET(smoothing), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX/8, FLAGS }, + { "independence", "proportion of independent to linked channel normalization", OFFSET(independence), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 1.0, FLAGS }, + { "strength", "strength of filter, from no effect to full normalization", OFFSET(strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 1.0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(normalize); + +// This function is the main guts of the filter. Normalizes the input frame +// into the output frame. The frames are known to have the same dimensions +// and pixel format. +static void normalize(NormalizeContext *s, AVFrame *in, AVFrame *out) +{ + // Per-extremum, per-channel local variables. + struct { + uint8_t in; // Original input byte value for this frame. + float smoothed; // Smoothed input value [0,255]. + float out; // Output value [0,255]. + } min[3], max[3]; // Min and max for each channel in {R,G,B}. + + float rgb_min_smoothed; // Min input range for linked normalization + float rgb_max_smoothed; // Max input range for linked normalization + uint8_t lut[3][256]; // Lookup table + int x, y, c; + + // First, scan the input frame to find, for each channel, the minimum + // (min.in) and maximum (max.in) values present in the channel. + for (c = 0; c < 3; c++) + min[c].in = max[c].in = in->data[0][s->co[c]]; + for (y = 0; y < in->height; y++) { + uint8_t *inp = in->data[0] + y * in->linesize[0]; + uint8_t *outp = out->data[0] + y * out->linesize[0]; + for (x = 0; x < in->width; x++) { + for (c = 0; c < 3; c++) { + min[c].in = FFMIN(min[c].in, inp[s->co[c]]); + max[c].in = FFMAX(max[c].in, inp[s->co[c]]); + } + inp += s->num_components; + outp += s->num_components; + } + } + + // Next, for each channel, push min.in and max.in into their respective + // histories, to determine the min.smoothed and max.smoothed for this frame. + { + int history_idx = s->frame_num % s->history_len; + // Assume the history is not yet full; num_history_vals is the number + // of frames received so far including the current frame. + int num_history_vals = s->frame_num + 1; + if (s->frame_num >= s->history_len) { + //The history is full; drop oldest value and cap num_history_vals. + for (c = 0; c < 3; c++) { + s->min[c].history_sum -= s->min[c].history[history_idx]; + s->max[c].history_sum -= s->max[c].history[history_idx]; + } + num_history_vals = s->history_len; + } + // For each extremum, update history_sum and calculate smoothed value + // as the rolling average of the history entries. + for (c = 0; c < 3; c++) { + s->min[c].history_sum += (s->min[c].history[history_idx] = min[c].in); + min[c].smoothed = s->min[c].history_sum / (float)num_history_vals; + s->max[c].history_sum += (s->max[c].history[history_idx] = max[c].in); + max[c].smoothed = s->max[c].history_sum / (float)num_history_vals; + } + } + + // Determine the input range for linked normalization. This is simply the + // minimum of the per-channel minimums, and the maximum of the per-channel + // maximums. + rgb_min_smoothed = FFMIN3(min[0].smoothed, min[1].smoothed, min[2].smoothed); + rgb_max_smoothed = FFMAX3(max[0].smoothed, max[1].smoothed, max[2].smoothed); + + // Now, process each channel to determine the input and output range and + // build the lookup tables. + for (c = 0; c < 3; c++) { + int in_val; + // Adjust the input range for this channel [min.smoothed,max.smoothed] + // by mixing in the correct proportion of the linked normalization + // input range [rgb_min_smoothed,rgb_max_smoothed]. + min[c].smoothed = (min[c].smoothed * s->independence) + + (rgb_min_smoothed * (1.0f - s->independence)); + max[c].smoothed = (max[c].smoothed * s->independence) + + (rgb_max_smoothed * (1.0f - s->independence)); + + // Calculate the output range [min.out,max.out] as a ratio of the full- + // strength output range [blackpt,whitept] and the original input range + // [min.in,max.in], based on the user-specified filter strength. + min[c].out = (s->blackpt[c] * s->strength) + + (min[c].in * (1.0f - s->strength)); + max[c].out = (s->whitept[c] * s->strength) + + (max[c].in * (1.0f - s->strength)); + + // Now, build a lookup table which linearly maps the adjusted input range + // [min.smoothed,max.smoothed] to the output range [min.out,max.out]. + // Perform the linear interpolation for each x: + // lut[x] = (int)(float(x - min.smoothed) * scale + max.out + 0.5) + // where scale = (max.out - min.out) / (max.smoothed - min.smoothed) + if (min[c].smoothed == max[c].smoothed) { + // There is no dynamic range to expand. No mapping for this channel. + for (in_val = min[c].in; in_val <= max[c].in; in_val++) + lut[c][in_val] = min[c].out; + } else { + // We must set lookup values for all values in the original input + // range [min.in,max.in]. Since the original input range may be + // larger than [min.smoothed,max.smoothed], some output values may + // fall outside the [0,255] dynamic range. We need to clamp them. + float scale = (max[c].out - min[c].out) / (max[c].smoothed - min[c].smoothed); + for (in_val = min[c].in; in_val <= max[c].in; in_val++) { + int out_val = (in_val - min[c].smoothed) * scale + min[c].out + 0.5f; + out_val = FFMAX(out_val, 0); + out_val = FFMIN(out_val, 255); + lut[c][in_val] = out_val; + } + } + } + + // Finally, process the pixels of the input frame using the lookup tables. + for (y = 0; y < in->height; y++) { + uint8_t *inp = in->data[0] + y * in->linesize[0]; + uint8_t *outp = out->data[0] + y * out->linesize[0]; + for (x = 0; x < in->width; x++) { + for (c = 0; c < 3; c++) + outp[s->co[c]] = lut[c][inp[s->co[c]]]; + if (s->num_components == 4) + // Copy alpha as-is. + outp[s->co[3]] = inp[s->co[3]]; + inp += s->num_components; + outp += s->num_components; + } + } + + s->frame_num++; +} + +// Now we define all the functions accessible from the ff_vf_normalize class, +// which is ffmpeg's interface to our filter. See doc/filter_design.txt and +// doc/writing_filters.txt for descriptions of what these interface functions +// are expected to do. + +// Set the pixel formats that our filter supports. We should be able to process +// any 8-bit RGB formats. 16-bit support might be useful one day. +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_RGB24, + AV_PIX_FMT_BGR24, + AV_PIX_FMT_ARGB, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_ABGR, + AV_PIX_FMT_BGRA, + AV_PIX_FMT_0RGB, + AV_PIX_FMT_RGB0, + AV_PIX_FMT_0BGR, + AV_PIX_FMT_BGR0, + AV_PIX_FMT_NONE + }; + // According to filter_design.txt, using ff_set_common_formats() this way + // ensures the pixel formats of the input and output will be the same. That + // saves a bit of effort possibly needing to handle format conversions. + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +// At this point we know the pixel format used for both input and output. We +// can also access the frame rate of the input video and allocate some memory +// appropriately +static int config_input(AVFilterLink *inlink) +{ + NormalizeContext *s = inlink->dst->priv; + // Store offsets to R,G,B,A bytes respectively in each pixel + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int c; + + for (c = 0; c < 4; ++c) + s->co[c] = desc->comp[c].offset; + s->num_components = desc->nb_components; + // Convert smoothing value to history_len (a count of frames to average, + // must be at least 1). Currently this is a direct assignment, but the + // smoothing value was originally envisaged as a number of seconds. In + // future it would be nice to set history_len using a number of seconds, + // but VFR video is currently an obstacle to doing so. + s->history_len = s->smoothing + 1; + // Allocate the history buffers -- there are 6 -- one for each extrema. + // s->smoothing is limited to INT_MAX/8, so that (s->history_len * 6) + // can't overflow on 32bit causing a too-small allocation. + s->history_mem = av_malloc(s->history_len * 6); + if (s->history_mem == NULL) + return AVERROR(ENOMEM); + + for (c = 0; c < 3; c++) { + s->min[c].history = s->history_mem + (c*2) * s->history_len; + s->max[c].history = s->history_mem + (c*2+1) * s->history_len; + } + return 0; +} + +// Free any memory allocations here +static av_cold void uninit(AVFilterContext *ctx) +{ + NormalizeContext *s = ctx->priv; + + av_freep(&s->history_mem); +} + +// This function is pretty much standard from doc/writing_filters.txt. It +// tries to do in-place filtering where possible, only allocating a new output +// frame when absolutely necessary. +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + NormalizeContext *s = ctx->priv; + AVFrame *out; + // Set 'direct' if we can modify the input frame in-place. Otherwise we + // need to retrieve a new frame from the output link. + int direct = av_frame_is_writable(in) && !ctx->is_disabled; + + if (direct) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + // Now we've got the input and output frames (which may be the same frame) + // perform the filtering with our custom function. + normalize(s, in, out); + + if (ctx->is_disabled) { + av_frame_free(&out); + return ff_filter_frame(outlink, in); + } + + if (!direct) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_normalize = { + .name = "normalize", + .description = NULL_IF_CONFIG_SMALL("Normalize RGB video."), + .priv_size = sizeof(NormalizeContext), + .priv_class = &normalize_class, + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/vf_ocr.c b/libavfilter/vf_ocr.c index e003982f0..abfff4943 100644 --- a/libavfilter/vf_ocr.c +++ b/libavfilter/vf_ocr.c @@ -90,9 +90,7 @@ static int query_formats(AVFilterContext *ctx) AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); if (!fmts_list) return AVERROR(ENOMEM); - ff_set_common_formats(ctx, fmts_list); - - return 0; + return ff_set_common_formats(ctx, fmts_list); } static int filter_frame(AVFilterLink *inlink, AVFrame *in) diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c index 5bf3d66cf..aa5835ae3 100644 --- a/libavfilter/vf_overlay.c +++ b/libavfilter/vf_overlay.c @@ -109,6 +109,7 @@ typedef struct OverlayContext { uint8_t overlay_rgba_map[4]; uint8_t overlay_has_alpha; int format; ///< OverlayFormat + int alpha_format; int eval_mode; ///< EvalMode FFFrameSync fs; @@ -401,9 +402,10 @@ static int config_output(AVFilterLink *outlink) * Blend image in src to destination buffer dst at position (x, y). */ -static void blend_image_packed_rgb(AVFilterContext *ctx, +static av_always_inline void blend_image_packed_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, - int main_has_alpha, int x, int y) + int main_has_alpha, int x, int y, + int is_straight) { OverlayContext *s = ctx->priv; int i, imax, j, jmax; @@ -454,9 +456,12 @@ static void blend_image_packed_rgb(AVFilterContext *ctx, default: // main_value = main_value * (1 - alpha) + overlay_value * alpha // since alpha is in the range 0-255, the result must divided by 255 - d[dr] = FAST_DIV255(d[dr] * (255 - alpha) + S[sr] * alpha); - d[dg] = FAST_DIV255(d[dg] * (255 - alpha) + S[sg] * alpha); - d[db] = FAST_DIV255(d[db] * (255 - alpha) + S[sb] * alpha); + d[dr] = is_straight ? FAST_DIV255(d[dr] * (255 - alpha) + S[sr] * alpha) : + FFMIN(FAST_DIV255(d[dr] * (255 - alpha)) + S[sr], 255); + d[dg] = is_straight ? FAST_DIV255(d[dg] * (255 - alpha) + S[sg] * alpha) : + FFMIN(FAST_DIV255(d[dg] * (255 - alpha)) + S[sg], 255); + d[db] = is_straight ? FAST_DIV255(d[db] * (255 - alpha) + S[sb] * alpha) : + FFMIN(FAST_DIV255(d[db] * (255 - alpha)) + S[sb], 255); } if (main_has_alpha) { switch (alpha) { @@ -487,7 +492,9 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, int main_has_alpha, int dst_plane, int dst_offset, - int dst_step) + int dst_step, + int straight, + int yuv) { int src_wp = AV_CEIL_RSHIFT(src_w, hsub); int src_hp = AV_CEIL_RSHIFT(src_h, vsub); @@ -546,7 +553,14 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, alpha_d = da[0]; alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d); } - *d = FAST_DIV255(*d * (255 - alpha) + *s * alpha); + if (straight) { + *d = FAST_DIV255(*d * (255 - alpha) + *s * alpha); + } else { + if (i && yuv) + *d = av_clip(FAST_DIV255((*d - 128) * (255 - alpha)) + *s - 128, -128, 128) + 128; + else + *d = FFMIN(FAST_DIV255(*d * (255 - alpha)) + *s, 255); + } s++; d += dst_step; da += 1 << hsub; @@ -605,7 +619,8 @@ static av_always_inline void blend_image_yuv(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int hsub, int vsub, int main_has_alpha, - int x, int y) + int x, int y, + int is_straight) { OverlayContext *s = ctx->priv; const int src_w = src->width; @@ -614,11 +629,11 @@ static av_always_inline void blend_image_yuv(AVFilterContext *ctx, const int dst_h = dst->height; blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 0, 0, 0, x, y, main_has_alpha, - s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step); + s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 1); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 1, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step); + s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 1); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 2, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step); + s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 1); if (main_has_alpha) alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y); @@ -628,7 +643,8 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int hsub, int vsub, int main_has_alpha, - int x, int y) + int x, int y, + int is_straight) { OverlayContext *s = ctx->priv; const int src_w = src->width; @@ -637,11 +653,11 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, const int dst_h = dst->height; blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 0, 0, 0, x, y, main_has_alpha, - s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step); + s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 0); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 1, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step); + s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 0); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 2, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step); + s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 0); if (main_has_alpha) alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y); @@ -649,52 +665,102 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, static void blend_image_yuv420(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y); + blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y, 1); } static void blend_image_yuva420(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y); + blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y, 1); } static void blend_image_yuv422(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y); + blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y, 1); } static void blend_image_yuva422(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y); + blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y, 1); } static void blend_image_yuv444(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y); + blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y, 1); } static void blend_image_yuva444(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y); + blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y, 1); } static void blend_image_gbrp(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y); + blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y, 1); } static void blend_image_gbrap(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y); + blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y, 1); +} + +static void blend_image_yuv420_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y, 0); +} + +static void blend_image_yuva420_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y, 0); +} + +static void blend_image_yuv422_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y, 0); +} + +static void blend_image_yuva422_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y, 0); +} + +static void blend_image_yuv444_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y, 0); +} + +static void blend_image_yuva444_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y, 0); +} + +static void blend_image_gbrp_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y, 0); +} + +static void blend_image_gbrap_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y, 0); } static void blend_image_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_packed_rgb(ctx, dst, src, 0, x, y); + blend_image_packed_rgb(ctx, dst, src, 0, x, y, 1); } static void blend_image_rgba(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_packed_rgb(ctx, dst, src, 1, x, y); + blend_image_packed_rgb(ctx, dst, src, 1, x, y, 1); +} + +static void blend_image_rgb_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_packed_rgb(ctx, dst, src, 0, x, y, 0); +} + +static void blend_image_rgba_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_packed_rgb(ctx, dst, src, 1, x, y, 0); } static int config_input_main(AVFilterLink *inlink) @@ -754,6 +820,52 @@ static int config_input_main(AVFilterLink *inlink) } break; } + + if (!s->alpha_format) + return 0; + + switch (s->format) { + case OVERLAY_FORMAT_YUV420: + s->blend_image = s->main_has_alpha ? blend_image_yuva420_pm : blend_image_yuv420_pm; + break; + case OVERLAY_FORMAT_YUV422: + s->blend_image = s->main_has_alpha ? blend_image_yuva422_pm : blend_image_yuv422_pm; + break; + case OVERLAY_FORMAT_YUV444: + s->blend_image = s->main_has_alpha ? blend_image_yuva444_pm : blend_image_yuv444_pm; + break; + case OVERLAY_FORMAT_RGB: + s->blend_image = s->main_has_alpha ? blend_image_rgba_pm : blend_image_rgb_pm; + break; + case OVERLAY_FORMAT_GBRP: + s->blend_image = s->main_has_alpha ? blend_image_gbrap_pm : blend_image_gbrp_pm; + break; + case OVERLAY_FORMAT_AUTO: + switch (inlink->format) { + case AV_PIX_FMT_YUVA420P: + s->blend_image = blend_image_yuva420_pm; + break; + case AV_PIX_FMT_YUVA422P: + s->blend_image = blend_image_yuva422_pm; + break; + case AV_PIX_FMT_YUVA444P: + s->blend_image = blend_image_yuva444_pm; + break; + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_ABGR: + s->blend_image = blend_image_rgba_pm; + break; + case AV_PIX_FMT_GBRAP: + s->blend_image = blend_image_gbrap_pm; + break; + default: + av_assert0(0); + break; + } + break; + } return 0; } @@ -835,6 +947,9 @@ static const AVOption overlay_options[] = { { "gbrp", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_GBRP}, .flags = FLAGS, .unit = "format" }, { "auto", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_AUTO}, .flags = FLAGS, .unit = "format" }, { "repeatlast", "repeat overlay of the last overlay frame", OFFSET(fs.opt_repeatlast), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "alpha", "alpha format", OFFSET(alpha_format), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "alpha_format" }, + { "straight", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, .flags = FLAGS, .unit = "alpha_format" }, + { "premultiplied", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, .flags = FLAGS, .unit = "alpha_format" }, { NULL } }; diff --git a/libavfilter/vf_overlay_opencl.c b/libavfilter/vf_overlay_opencl.c new file mode 100644 index 000000000..ee8381dfe --- /dev/null +++ b/libavfilter/vf_overlay_opencl.c @@ -0,0 +1,361 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/buffer.h" +#include "libavutil/common.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_opencl.h" +#include "libavutil/log.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/opt.h" + +#include "avfilter.h" +#include "framesync.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +typedef struct OverlayOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + FFFrameSync fs; + + int nb_planes; + int x_subsample; + int y_subsample; + int alpha_separate; + + int x_position; + int y_position; +} OverlayOpenCLContext; + +static int overlay_opencl_load(AVFilterContext *avctx, + enum AVPixelFormat main_format, + enum AVPixelFormat overlay_format) +{ + OverlayOpenCLContext *ctx = avctx->priv; + cl_int cle; + const char *source = ff_opencl_source_overlay; + const char *kernel; + const AVPixFmtDescriptor *main_desc, *overlay_desc; + int err, i, main_planes, overlay_planes; + + main_desc = av_pix_fmt_desc_get(main_format); + overlay_desc = av_pix_fmt_desc_get(overlay_format); + + main_planes = overlay_planes = 0; + for (i = 0; i < main_desc->nb_components; i++) + main_planes = FFMAX(main_planes, + main_desc->comp[i].plane + 1); + for (i = 0; i < overlay_desc->nb_components; i++) + overlay_planes = FFMAX(overlay_planes, + overlay_desc->comp[i].plane + 1); + + ctx->nb_planes = main_planes; + ctx->x_subsample = 1 << main_desc->log2_chroma_w; + ctx->y_subsample = 1 << main_desc->log2_chroma_h; + + if (ctx->x_position % ctx->x_subsample || + ctx->y_position % ctx->y_subsample) { + av_log(avctx, AV_LOG_WARNING, "Warning: overlay position (%d, %d) " + "does not match subsampling (%d, %d).\n", + ctx->x_position, ctx->y_position, + ctx->x_subsample, ctx->y_subsample); + } + + if (main_planes == overlay_planes) { + if (main_desc->nb_components == overlay_desc->nb_components) + kernel = "overlay_no_alpha"; + else + kernel = "overlay_internal_alpha"; + ctx->alpha_separate = 0; + } else { + kernel = "overlay_external_alpha"; + ctx->alpha_separate = 1; + } + + av_log(avctx, AV_LOG_DEBUG, "Using kernel %s.\n", kernel); + + err = ff_opencl_filter_load_program(avctx, &source, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel = clCreateKernel(ctx->ocf.program, kernel, &cle); + if (!ctx->kernel) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int overlay_opencl_blend(FFFrameSync *fs) +{ + AVFilterContext *avctx = fs->parent; + AVFilterLink *outlink = avctx->outputs[0]; + OverlayOpenCLContext *ctx = avctx->priv; + AVFrame *input_main, *input_overlay; + AVFrame *output; + cl_mem mem; + cl_int cle, x, y; + size_t global_work[2]; + int kernel_arg = 0; + int err, plane; + + err = ff_framesync_get_frame(fs, 0, &input_main, 0); + if (err < 0) + return err; + err = ff_framesync_get_frame(fs, 1, &input_overlay, 0); + if (err < 0) + return err; + + if (!ctx->initialised) { + AVHWFramesContext *main_fc = + (AVHWFramesContext*)input_main->hw_frames_ctx->data; + AVHWFramesContext *overlay_fc = + (AVHWFramesContext*)input_overlay->hw_frames_ctx->data; + + err = overlay_opencl_load(avctx, main_fc->sw_format, + overlay_fc->sw_format); + if (err < 0) + return err; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (plane = 0; plane < ctx->nb_planes; plane++) { + kernel_arg = 0; + + mem = (cl_mem)output->data[plane]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + mem = (cl_mem)input_main->data[plane]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + mem = (cl_mem)input_overlay->data[plane]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + if (ctx->alpha_separate) { + mem = (cl_mem)input_overlay->data[ctx->nb_planes]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + } + + x = ctx->x_position / (plane == 0 ? 1 : ctx->x_subsample); + y = ctx->y_position / (plane == 0 ? 1 : ctx->y_subsample); + + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &x); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &y); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + if (ctx->alpha_separate) { + cl_int alpha_adj_x = plane == 0 ? 1 : ctx->x_subsample; + cl_int alpha_adj_y = plane == 0 ? 1 : ctx->y_subsample; + + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &alpha_adj_x); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &alpha_adj_y); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + } + + global_work[0] = output->width; + global_work[1] = output->height; + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue " + "overlay kernel for plane %d: %d.\n", cle, plane); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input_main); + + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail_kernel_arg: + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel arg %d: %d.\n", + kernel_arg, cle); + err = AVERROR(EIO); +fail: + av_frame_free(&output); + return err; +} + +static int overlay_opencl_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + OverlayOpenCLContext *ctx = avctx->priv; + int err; + + err = ff_opencl_filter_config_output(outlink); + if (err < 0) + return err; + + err = ff_framesync_init_dualinput(&ctx->fs, avctx); + if (err < 0) + return err; + + return ff_framesync_configure(&ctx->fs); +} + +static av_cold int overlay_opencl_init(AVFilterContext *avctx) +{ + OverlayOpenCLContext *ctx = avctx->priv; + + ctx->fs.on_event = &overlay_opencl_blend; + + return ff_opencl_filter_init(avctx); +} + +static int overlay_opencl_activate(AVFilterContext *avctx) +{ + OverlayOpenCLContext *ctx = avctx->priv; + + return ff_framesync_activate(&ctx->fs); +} + +static av_cold void overlay_opencl_uninit(AVFilterContext *avctx) +{ + OverlayOpenCLContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); + + ff_framesync_uninit(&ctx->fs); +} + +#define OFFSET(x) offsetof(OverlayOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption overlay_opencl_options[] = { + { "x", "Overlay x position", + OFFSET(x_position), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS }, + { "y", "Overlay y position", + OFFSET(y_position), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(overlay_opencl); + +static const AVFilterPad overlay_opencl_inputs[] = { + { + .name = "main", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_input, + }, + { + .name = "overlay", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad overlay_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &overlay_opencl_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_overlay_opencl = { + .name = "overlay_opencl", + .description = NULL_IF_CONFIG_SMALL("Overlay one video on top of another"), + .priv_size = sizeof(OverlayOpenCLContext), + .priv_class = &overlay_opencl_class, + .init = &overlay_opencl_init, + .uninit = &overlay_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .activate = &overlay_opencl_activate, + .inputs = overlay_opencl_inputs, + .outputs = overlay_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c new file mode 100644 index 000000000..6c3efdbeb --- /dev/null +++ b/libavfilter/vf_overlay_qsv.c @@ -0,0 +1,493 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 hardware accelerated overlay filter based on Intel Quick Sync Video VPP + */ + +#include "libavutil/opt.h" +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/eval.h" +#include "libavutil/hwcontext.h" +#include "libavutil/avstring.h" +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/mathematics.h" + +#include "internal.h" +#include "avfilter.h" +#include "formats.h" +#include "video.h" + +#include "qsvvpp.h" + +#define MAIN 0 +#define OVERLAY 1 + +#define OFFSET(x) offsetof(QSVOverlayContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) + +enum var_name { + VAR_MAIN_iW, VAR_MW, + VAR_MAIN_iH, VAR_MH, + VAR_OVERLAY_iW, + VAR_OVERLAY_iH, + VAR_OVERLAY_X, VAR_OX, + VAR_OVERLAY_Y, VAR_OY, + VAR_OVERLAY_W, VAR_OW, + VAR_OVERLAY_H, VAR_OH, + VAR_VARS_NB +}; + +enum EOFAction { + EOF_ACTION_REPEAT, + EOF_ACTION_ENDALL +}; + +typedef struct QSVOverlayContext { + const AVClass *class; + + QSVVPPContext *qsv; + QSVVPPParam qsv_param; + mfxExtVPPComposite comp_conf; + double var_values[VAR_VARS_NB]; + + char *overlay_ox, *overlay_oy, *overlay_ow, *overlay_oh; + uint16_t overlay_alpha, overlay_pixel_alpha; + + enum EOFAction eof_action; /* action to take on EOF from source */ + + AVFrame *main; + AVFrame *over_prev, *over_next; +} QSVOverlayContext; + +static const char *const var_names[] = { + "main_w", "W", /* input width of the main layer */ + "main_h", "H", /* input height of the main layer */ + "overlay_iw", /* input width of the overlay layer */ + "overlay_ih", /* input height of the overlay layer */ + "overlay_x", "x", /* x position of the overlay layer inside of main */ + "overlay_y", "y", /* y position of the overlay layer inside of main */ + "overlay_w", "w", /* output width of overlay layer */ + "overlay_h", "h", /* output height of overlay layer */ + NULL +}; + +static const AVOption options[] = { + { "x", "Overlay x position", OFFSET(overlay_ox), AV_OPT_TYPE_STRING, { .str="0"}, 0, 255, .flags = FLAGS}, + { "y", "Overlay y position", OFFSET(overlay_oy), AV_OPT_TYPE_STRING, { .str="0"}, 0, 255, .flags = FLAGS}, + { "w", "Overlay width", OFFSET(overlay_ow), AV_OPT_TYPE_STRING, { .str="overlay_iw"}, 0, 255, .flags = FLAGS}, + { "h", "Overlay height", OFFSET(overlay_oh), AV_OPT_TYPE_STRING, { .str="overlay_ih*w/overlay_iw"}, 0, 255, .flags = FLAGS}, + { "alpha", "Overlay global alpha", OFFSET(overlay_alpha), AV_OPT_TYPE_INT, { .i64 = 255}, 0, 255, .flags = FLAGS}, + { "eof_action", "Action to take when encountering EOF from secondary input ", + OFFSET(eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT }, + EOF_ACTION_REPEAT, EOF_ACTION_ENDALL, .flags = FLAGS, "eof_action" }, + { "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" }, + { "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" }, + { NULL } +}; + +static int eval_expr(AVFilterContext *ctx) +{ + QSVOverlayContext *vpp = ctx->priv; + double *var_values = vpp->var_values; + int ret = 0; + AVExpr *ox_expr = NULL, *oy_expr = NULL; + AVExpr *ow_expr = NULL, *oh_expr = NULL; + +#define PASS_EXPR(e, s) {\ + ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \ + if (ret < 0) {\ + av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\ + goto release;\ + }\ +} + PASS_EXPR(ox_expr, vpp->overlay_ox); + PASS_EXPR(oy_expr, vpp->overlay_oy); + PASS_EXPR(ow_expr, vpp->overlay_ow); + PASS_EXPR(oh_expr, vpp->overlay_oh); +#undef PASS_EXPR + + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + var_values[VAR_OVERLAY_H] = + var_values[VAR_OH] = av_expr_eval(oh_expr, var_values, NULL); + + /* calc again in case ow is relative to oh */ + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + + var_values[VAR_OVERLAY_X] = + var_values[VAR_OX] = av_expr_eval(ox_expr, var_values, NULL); + var_values[VAR_OVERLAY_Y] = + var_values[VAR_OY] = av_expr_eval(oy_expr, var_values, NULL); + + /* calc again in case ox is relative to oy */ + var_values[VAR_OVERLAY_X] = + var_values[VAR_OX] = av_expr_eval(ox_expr, var_values, NULL); + + /* calc overlay_w and overlay_h again incase relative to ox,oy */ + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + var_values[VAR_OVERLAY_H] = + var_values[VAR_OH] = av_expr_eval(oh_expr, var_values, NULL); + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + +release: + av_expr_free(ox_expr); + av_expr_free(oy_expr); + av_expr_free(ow_expr); + av_expr_free(oh_expr); + + return ret; +} + +static int have_alpha_planar(AVFilterLink *link) +{ + enum AVPixelFormat pix_fmt; + const AVPixFmtDescriptor *desc; + AVHWFramesContext *fctx; + + if (link->format == AV_PIX_FMT_QSV) { + fctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + pix_fmt = fctx->sw_format; + } + + desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return 0; + + return !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); +} + +static int config_main_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + QSVOverlayContext *vpp = ctx->priv; + mfxVPPCompInputStream *st = &vpp->comp_conf.InputStream[0]; + + av_log(ctx, AV_LOG_DEBUG, "Input[%d] is of %s.\n", FF_INLINK_IDX(inlink), + av_get_pix_fmt_name(inlink->format)); + + vpp->var_values[VAR_MAIN_iW] = + vpp->var_values[VAR_MW] = inlink->w; + vpp->var_values[VAR_MAIN_iH] = + vpp->var_values[VAR_MH] = inlink->h; + + st->DstX = 0; + st->DstY = 0; + st->DstW = inlink->w; + st->DstH = inlink->h; + st->GlobalAlphaEnable = 0; + st->PixelAlphaEnable = 0; + + return 0; +} + +static int config_overlay_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + QSVOverlayContext *vpp = ctx->priv; + mfxVPPCompInputStream *st = &vpp->comp_conf.InputStream[1]; + int ret = 0; + + av_log(ctx, AV_LOG_DEBUG, "Input[%d] is of %s.\n", FF_INLINK_IDX(inlink), + av_get_pix_fmt_name(inlink->format)); + + vpp->var_values[VAR_OVERLAY_iW] = inlink->w; + vpp->var_values[VAR_OVERLAY_iH] = inlink->h; + + ret = eval_expr(ctx); + if (ret < 0) + return ret; + + st->DstX = vpp->var_values[VAR_OX]; + st->DstY = vpp->var_values[VAR_OY]; + st->DstW = vpp->var_values[VAR_OW]; + st->DstH = vpp->var_values[VAR_OH]; + st->GlobalAlpha = vpp->overlay_alpha; + st->GlobalAlphaEnable = (st->GlobalAlpha < 255); + st->PixelAlphaEnable = have_alpha_planar(inlink); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + QSVOverlayContext *vpp = ctx->priv; + AVFilterLink *in0 = ctx->inputs[0]; + AVFilterLink *in1 = ctx->inputs[1]; + + av_log(ctx, AV_LOG_DEBUG, "Output is of %s.\n", av_get_pix_fmt_name(outlink->format)); + if ((in0->format == AV_PIX_FMT_QSV && in1->format != AV_PIX_FMT_QSV) || + (in0->format != AV_PIX_FMT_QSV && in1->format == AV_PIX_FMT_QSV)) { + av_log(ctx, AV_LOG_ERROR, "Mixing hardware and software pixel formats is not supported.\n"); + return AVERROR(EINVAL); + } else if (in0->format == AV_PIX_FMT_QSV) { + AVHWFramesContext *hw_frame0 = (AVHWFramesContext *)in0->hw_frames_ctx->data; + AVHWFramesContext *hw_frame1 = (AVHWFramesContext *)in1->hw_frames_ctx->data; + + if (hw_frame0->device_ctx != hw_frame1->device_ctx) { + av_log(ctx, AV_LOG_ERROR, "Inputs with different underlying QSV devices are forbidden.\n"); + return AVERROR(EINVAL); + } + } + + outlink->w = vpp->var_values[VAR_MW]; + outlink->h = vpp->var_values[VAR_MH]; + outlink->frame_rate = in0->frame_rate; + outlink->time_base = av_inv_q(outlink->frame_rate); + + return ff_qsvvpp_create(ctx, &vpp->qsv, &vpp->qsv_param); +} + +static int blend_frame(AVFilterContext *ctx, AVFrame *mpic, AVFrame *opic) +{ + int ret = 0; + QSVOverlayContext *vpp = ctx->priv; + AVFrame *opic_copy = NULL; + + ret = ff_qsvvpp_filter_frame(vpp->qsv, ctx->inputs[0], mpic); + if (ret == 0 || ret == AVERROR(EAGAIN)) { + /* Reference the overlay frame. Because: + * 1. ff_qsvvpp_filter_frame will take control of the given frame + * 2. We need to repeat the overlay frame when 2nd input goes into EOF + */ + opic_copy = av_frame_clone(opic); + if (!opic_copy) + return AVERROR(ENOMEM); + + ret = ff_qsvvpp_filter_frame(vpp->qsv, ctx->inputs[1], opic_copy); + } + + return ret; +} + +static int handle_overlay_eof(AVFilterContext *ctx) +{ + int ret = 0; + QSVOverlayContext *s = ctx->priv; + /* Repeat previous frame on secondary input */ + if (s->over_prev && s->eof_action == EOF_ACTION_REPEAT) + ret = blend_frame(ctx, s->main, s->over_prev); + /* End both streams */ + else if (s->eof_action == EOF_ACTION_ENDALL) + return AVERROR_EOF; + + s->main = NULL; + + return ret; +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + QSVOverlayContext *s = ctx->priv; + AVRational tb_main = ctx->inputs[MAIN]->time_base; + AVRational tb_over = ctx->inputs[OVERLAY]->time_base; + int ret = 0; + + /* get a frame on the main input */ + if (!s->main) { + ret = ff_request_frame(ctx->inputs[MAIN]); + if (ret < 0) + return ret; + } + + /* get a new frame on the overlay input, on EOF check setting 'eof_action' */ + if (!s->over_next) { + ret = ff_request_frame(ctx->inputs[OVERLAY]); + if (ret == AVERROR_EOF) + return handle_overlay_eof(ctx); + else if (ret < 0) + return ret; + } + + while (s->main->pts != AV_NOPTS_VALUE && + s->over_next->pts != AV_NOPTS_VALUE && + av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main) < 0) { + av_frame_free(&s->over_prev); + FFSWAP(AVFrame*, s->over_prev, s->over_next); + + ret = ff_request_frame(ctx->inputs[OVERLAY]); + if (ret == AVERROR_EOF) + return handle_overlay_eof(ctx); + else if (ret < 0) + return ret; + } + + if (s->main->pts == AV_NOPTS_VALUE || + s->over_next->pts == AV_NOPTS_VALUE || + !av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main)) { + ret = blend_frame(ctx, s->main, s->over_next); + av_frame_free(&s->over_prev); + FFSWAP(AVFrame*, s->over_prev, s->over_next); + } else if (s->over_prev) { + ret = blend_frame(ctx, s->main, s->over_prev); + } else { + av_frame_free(&s->main); + ret = AVERROR(EAGAIN); + } + + s->main = NULL; + + return ret; +} + +static int filter_frame_main(AVFilterLink *inlink, AVFrame *frame) +{ + QSVOverlayContext *s = inlink->dst->priv; + + av_assert0(!s->main); + s->main = frame; + + return 0; +} + +static int filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame) +{ + QSVOverlayContext *s = inlink->dst->priv; + + av_assert0(!s->over_next); + s->over_next = frame; + + return 0; +} + +static int overlay_qsv_init(AVFilterContext *ctx) +{ + QSVOverlayContext *vpp = ctx->priv; + + /* fill composite config */ + vpp->comp_conf.Header.BufferId = MFX_EXTBUFF_VPP_COMPOSITE; + vpp->comp_conf.Header.BufferSz = sizeof(vpp->comp_conf); + vpp->comp_conf.NumInputStream = ctx->nb_inputs; + vpp->comp_conf.InputStream = av_mallocz_array(ctx->nb_inputs, + sizeof(*vpp->comp_conf.InputStream)); + if (!vpp->comp_conf.InputStream) + return AVERROR(ENOMEM); + + /* initialize QSVVPP params */ + vpp->qsv_param.filter_frame = NULL; + vpp->qsv_param.ext_buf = av_mallocz(sizeof(*vpp->qsv_param.ext_buf)); + if (!vpp->qsv_param.ext_buf) + return AVERROR(ENOMEM); + + vpp->qsv_param.ext_buf[0] = (mfxExtBuffer *)&vpp->comp_conf; + vpp->qsv_param.num_ext_buf = 1; + vpp->qsv_param.out_sw_format = AV_PIX_FMT_NV12; + vpp->qsv_param.num_crop = 0; + + return 0; +} + +static void overlay_qsv_uninit(AVFilterContext *ctx) +{ + QSVOverlayContext *vpp = ctx->priv; + + av_frame_free(&vpp->main); + av_frame_free(&vpp->over_prev); + av_frame_free(&vpp->over_next); + ff_qsvvpp_free(&vpp->qsv); + av_freep(&vpp->comp_conf.InputStream); + av_freep(&vpp->qsv_param.ext_buf); +} + +static int overlay_qsv_query_formats(AVFilterContext *ctx) +{ + int i; + int ret; + + static const enum AVPixelFormat main_in_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUYV422, + AV_PIX_FMT_RGB32, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat out_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + + for (i = 0; i < ctx->nb_inputs; i++) { + ret = ff_formats_ref(ff_make_format_list(main_in_fmts), &ctx->inputs[i]->out_formats); + if (ret < 0) + return ret; + } + + ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats); + if (ret < 0) + return ret; + + return 0; +} + +static const AVClass overlay_qsv_class = { + .class_name = "overlay_qsv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVFilterPad overlay_qsv_inputs[] = { + { + .name = "main", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame_main, + .config_props = config_main_input, + .needs_fifo = 1, + }, + { + .name = "overlay", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame_overlay, + .config_props = config_overlay_input, + .needs_fifo = 1, + }, + { NULL } +}; + +static const AVFilterPad overlay_qsv_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + .request_frame = request_frame, + }, + { NULL } +}; + +AVFilter ff_vf_overlay_qsv = { + .name = "overlay_qsv", + .description = NULL_IF_CONFIG_SMALL("Quick Sync Video overlay."), + .priv_size = sizeof(QSVOverlayContext), + .query_formats = overlay_qsv_query_formats, + .init = overlay_qsv_init, + .uninit = overlay_qsv_uninit, + .inputs = overlay_qsv_inputs, + .outputs = overlay_qsv_outputs, + .priv_class = &overlay_qsv_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c index 03de31734..5ff73e6b2 100644 --- a/libavfilter/vf_palettegen.c +++ b/libavfilter/vf_palettegen.c @@ -27,6 +27,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/qsort.h" +#include "libavutil/intreadwrite.h" #include "avfilter.h" #include "internal.h" @@ -74,6 +75,7 @@ typedef struct PaletteGenContext { struct range_box boxes[256]; // define the segmentation of the colorspace (the final palette) int nb_boxes; // number of boxes (increase will segmenting them) int palette_pushed; // if the palette frame is pushed into the outlink or not + uint8_t transparency_color[4]; // background color for transparency } PaletteGenContext; #define OFFSET(x) offsetof(PaletteGenContext, x) @@ -81,6 +83,7 @@ typedef struct PaletteGenContext { static const AVOption palettegen_options[] = { { "max_colors", "set the maximum number of colors to use in the palette", OFFSET(max_colors), AV_OPT_TYPE_INT, {.i64=256}, 4, 256, FLAGS }, { "reserve_transparent", "reserve a palette entry for transparency", OFFSET(reserve_transparent), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "transparency_color", "set a background color for transparency", OFFSET(transparency_color), AV_OPT_TYPE_COLOR, {.str="lime"}, CHAR_MIN, CHAR_MAX, FLAGS }, { "stats_mode", "set statistics mode", OFFSET(stats_mode), AV_OPT_TYPE_INT, {.i64=STATS_MODE_ALL_FRAMES}, 0, NB_STATS_MODE-1, FLAGS, "mode" }, { "full", "compute full frame histograms", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_ALL_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" }, { "diff", "compute histograms only for the part that differs from previous frame", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_DIFF_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" }, @@ -250,7 +253,7 @@ static void write_palette(AVFilterContext *ctx, AVFrame *out) if (s->reserve_transparent) { av_assert0(s->nb_boxes < 256); - pal[out->width - pal_linesize - 1] = 0x0000ff00; // add a green transparent color + pal[out->width - pal_linesize - 1] = AV_RB32(&s->transparency_color) >> 8; } } diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c index 79a067289..604a8af29 100644 --- a/libavfilter/vf_paletteuse.c +++ b/libavfilter/vf_paletteuse.c @@ -56,7 +56,7 @@ enum diff_mode { }; struct color_node { - uint8_t val[3]; + uint8_t val[4]; uint8_t palette_id; int split; int left_id, right_id; @@ -86,6 +86,8 @@ typedef struct PaletteUseContext { struct cache_node cache[CACHE_SIZE]; /* lookup cache */ struct color_node map[AVPALETTE_COUNT]; /* 3D-Tree (KD-Tree with K=3) for reverse colormap */ uint32_t palette[AVPALETTE_COUNT]; + int transparency_index; /* index in the palette of transparency. -1 if there is no transparency in the palette. */ + int trans_thresh; int palette_loaded; int dither; int new; @@ -116,6 +118,8 @@ static const AVOption paletteuse_options[] = { { "bayer_scale", "set scale for bayer dithering", OFFSET(bayer_scale), AV_OPT_TYPE_INT, {.i64=2}, 0, 5, FLAGS }, { "diff_mode", "set frame difference mode", OFFSET(diff_mode), AV_OPT_TYPE_INT, {.i64=DIFF_MODE_NONE}, 0, NB_DIFF_MODE-1, FLAGS, "diff_mode" }, { "rectangle", "process smallest different rectangle", 0, AV_OPT_TYPE_CONST, {.i64=DIFF_MODE_RECTANGLE}, INT_MIN, INT_MAX, FLAGS, "diff_mode" }, + { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, + { "alpha_threshold", "set the alpha threshold for transparency", OFFSET(trans_thresh), AV_OPT_TYPE_INT, {.i64=128}, 0, 255 }, /* following are the debug options, not part of the official API */ { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, @@ -125,7 +129,6 @@ static const AVOption paletteuse_options[] = { { "bruteforce", "brute-force into the palette", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE}, INT_MIN, INT_MAX, FLAGS, "search" }, { "mean_err", "compute and print mean error", OFFSET(calc_mean_err), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { "debug_accuracy", "test color search accuracy", OFFSET(debug_accuracy), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, - { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { NULL } }; @@ -157,34 +160,43 @@ static int query_formats(AVFilterContext *ctx) static av_always_inline int dither_color(uint32_t px, int er, int eg, int eb, int scale, int shift) { - return av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<> 24 ) << 24 + | av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<> 8 & 0xff) + ((eg * scale) / (1<= trans_thresh && c2[0] >= trans_thresh) { + return dr*dr + dg*dg + db*db; + } else { + return 255*255 + 255*255 + 255*255; + } } -static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *rgb) +static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *argb, const int trans_thresh) { int i, pal_id = -1, min_dist = INT_MAX; for (i = 0; i < AVPALETTE_COUNT; i++) { const uint32_t c = palette[i]; - if ((c & 0xff000000) == 0xff000000) { // ignore transparent entry - const uint8_t palrgb[] = { + if (c >> 24 >= trans_thresh) { // ignore transparent entry + const uint8_t palargb[] = { + palette[i]>>24 & 0xff, palette[i]>>16 & 0xff, palette[i]>> 8 & 0xff, palette[i] & 0xff, }; - const int d = diff(palrgb, rgb); + const int d = diff(palargb, argb, trans_thresh); if (d < min_dist) { pal_id = i; min_dist = d; @@ -203,13 +215,14 @@ struct nearest_color { static void colormap_nearest_node(const struct color_node *map, const int node_pos, const uint8_t *target, + const int trans_thresh, struct nearest_color *nearest) { const struct color_node *kd = map + node_pos; const int s = kd->split; int dx, nearer_kd_id, further_kd_id; const uint8_t *current = kd->val; - const int current_to_target = diff(target, current); + const int current_to_target = diff(target, current, trans_thresh); if (current_to_target < nearest->dist_sqd) { nearest->node_pos = node_pos; @@ -223,17 +236,17 @@ static void colormap_nearest_node(const struct color_node *map, else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id; if (nearer_kd_id != -1) - colormap_nearest_node(map, nearer_kd_id, target, nearest); + colormap_nearest_node(map, nearer_kd_id, target, trans_thresh, nearest); if (further_kd_id != -1 && dx*dx < nearest->dist_sqd) - colormap_nearest_node(map, further_kd_id, target, nearest); + colormap_nearest_node(map, further_kd_id, target, trans_thresh, nearest); } } -static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb) +static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb, const int trans_thresh) { struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1}; - colormap_nearest_node(node, 0, rgb, &res); + colormap_nearest_node(node, 0, rgb, trans_thresh, &res); return node[res.node_pos].palette_id; } @@ -242,7 +255,7 @@ struct stack_node { int dx2; }; -static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target) +static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target, const int trans_thresh) { int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0; struct stack_node nodes[16]; @@ -252,7 +265,7 @@ static av_always_inline uint8_t colormap_nearest_iterative(const struct color_no const struct color_node *kd = &root[cur_color_id]; const uint8_t *current = kd->val; - const int current_to_target = diff(target, current); + const int current_to_target = diff(target, current, trans_thresh); /* Compare current color node to the target and update our best node if * it's actually better. */ @@ -314,32 +327,35 @@ end: return root[best_node_id].palette_id; } -#define COLORMAP_NEAREST(search, palette, root, target) \ - search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target) : \ - search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target) : \ - colormap_nearest_bruteforce(palette, target) +#define COLORMAP_NEAREST(search, palette, root, target, trans_thresh) \ + search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target, trans_thresh) : \ + search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target, trans_thresh) : \ + colormap_nearest_bruteforce(palette, target, trans_thresh) /** * Check if the requested color is in the cache already. If not, find it in the * color tree and cache it. - * Note: r, g, and b are the component of c but are passed as well to avoid + * Note: a, r, g, and b are the components of color, but are passed as well to avoid * recomputing them (they are generally computed by the caller for other uses). */ -static av_always_inline int color_get(struct cache_node *cache, uint32_t color, - uint8_t r, uint8_t g, uint8_t b, - const struct color_node *map, - const uint32_t *palette, +static av_always_inline int color_get(PaletteUseContext *s, uint32_t color, + uint8_t a, uint8_t r, uint8_t g, uint8_t b, const enum color_search_method search_method) { int i; - const uint8_t rgb[] = {r, g, b}; + const uint8_t argb_elts[] = {a, r, g, b}; const uint8_t rhash = r & ((1<cache[hash]; struct cached_color *e; + // first, check for transparency + if (a < s->trans_thresh && s->transparency_index >= 0) { + return s->transparency_index; + } + for (i = 0; i < node->nb_entries; i++) { e = &node->entries[i]; if (e->color == color) @@ -351,21 +367,24 @@ static av_always_inline int color_get(struct cache_node *cache, uint32_t color, if (!e) return AVERROR(ENOMEM); e->color = color; - e->pal_entry = COLORMAP_NEAREST(search_method, palette, map, rgb); + e->pal_entry = COLORMAP_NEAREST(search_method, s->palette, s->map, argb_elts, s->trans_thresh); + return e->pal_entry; } -static av_always_inline int get_dst_color_err(struct cache_node *cache, - uint32_t c, const struct color_node *map, - const uint32_t *palette, - int *er, int *eg, int *eb, +static av_always_inline int get_dst_color_err(PaletteUseContext *s, + uint32_t c, int *er, int *eg, int *eb, const enum color_search_method search_method) { + const uint8_t a = c >> 24 & 0xff; const uint8_t r = c >> 16 & 0xff; const uint8_t g = c >> 8 & 0xff; const uint8_t b = c & 0xff; - const int dstx = color_get(cache, c, r, g, b, map, palette, search_method); - const uint32_t dstc = palette[dstx]; + uint32_t dstc; + const int dstx = color_get(s, c, a, r, g, b, search_method); + if (dstx < 0) + return dstx; + dstc = s->palette[dstx]; *er = r - (dstc >> 16 & 0xff); *eg = g - (dstc >> 8 & 0xff); *eb = b - (dstc & 0xff); @@ -378,9 +397,6 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram const enum color_search_method search_method) { int x, y; - const struct color_node *map = s->map; - struct cache_node *cache = s->cache; - const uint32_t *palette = s->palette; const int src_linesize = in ->linesize[0] >> 2; const int dst_linesize = out->linesize[0]; uint32_t *src = ((uint32_t *)in ->data[0]) + y_start*src_linesize; @@ -395,14 +411,14 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram if (dither == DITHERING_BAYER) { const int d = s->ordered_dither[(y & 7)<<3 | (x & 7)]; + const uint8_t a8 = src[x] >> 24 & 0xff; const uint8_t r8 = src[x] >> 16 & 0xff; const uint8_t g8 = src[x] >> 8 & 0xff; const uint8_t b8 = src[x] & 0xff; const uint8_t r = av_clip_uint8(r8 + d); const uint8_t g = av_clip_uint8(g8 + d); const uint8_t b = av_clip_uint8(b8 + d); - const uint32_t c = r<<16 | g<<8 | b; - const int color = color_get(cache, c, r, g, b, map, palette, search_method); + const int color = color_get(s, src[x], a8, r, g, b, search_method); if (color < 0) return color; @@ -410,7 +426,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_HECKBERT) { const int right = x < w - 1, down = y < h - 1; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -422,7 +438,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_FLOYD_STEINBERG) { const int right = x < w - 1, down = y < h - 1, left = x > x_start; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -436,7 +452,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_SIERRA2) { const int right = x < w - 1, down = y < h - 1, left = x > x_start; const int right2 = x < w - 2, left2 = x > x_start + 1; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -455,7 +471,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_SIERRA2_4A) { const int right = x < w - 1, down = y < h - 1, left = x > x_start; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -466,10 +482,11 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 1, 2); } else { + const uint8_t a = src[x] >> 24 & 0xff; const uint8_t r = src[x] >> 16 & 0xff; const uint8_t g = src[x] >> 8 & 0xff; const uint8_t b = src[x] & 0xff; - const int color = color_get(cache, src[x] & 0xffffff, r, g, b, map, palette, search_method); + const int color = color_get(s, src[x], a, r, g, b, search_method); if (color < 0) return color; @@ -489,19 +506,20 @@ static void disp_node(AVBPrint *buf, int depth) { const struct color_node *node = &map[node_id]; - const uint32_t fontcolor = node->val[0] > 0x50 && - node->val[1] > 0x50 && - node->val[2] > 0x50 ? 0 : 0xffffff; + const uint32_t fontcolor = node->val[1] > 0x50 && + node->val[2] > 0x50 && + node->val[3] > 0x50 ? 0 : 0xffffff; + const int rgb_comp = node->split - 1; av_bprintf(buf, "%*cnode%d [" "label=\"%c%02X%c%02X%c%02X%c\" " "fillcolor=\"#%02x%02x%02x\" " "fontcolor=\"#%06"PRIX32"\"]\n", depth*INDENT, ' ', node->palette_id, - "[ "[node->split], node->val[0], - "][ "[node->split], node->val[1], - " ]["[node->split], node->val[2], - " ]"[node->split], - node->val[0], node->val[1], node->val[2], + "[ "[rgb_comp], node->val[1], + "][ "[rgb_comp], node->val[2], + " ]["[rgb_comp], node->val[3], + " ]"[rgb_comp], + node->val[1], node->val[2], node->val[3], fontcolor); if (parent_id != -1) av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ', @@ -536,7 +554,7 @@ static int disp_tree(const struct color_node *node, const char *fname) return 0; } -static int debug_accuracy(const struct color_node *node, const uint32_t *palette, +static int debug_accuracy(const struct color_node *node, const uint32_t *palette, const int trans_thresh, const enum color_search_method search_method) { int r, g, b, ret = 0; @@ -544,16 +562,16 @@ static int debug_accuracy(const struct color_node *node, const uint32_t *palette for (r = 0; r < 256; r++) { for (g = 0; g < 256; g++) { for (b = 0; b < 256; b++) { - const uint8_t rgb[] = {r, g, b}; - const int r1 = COLORMAP_NEAREST(search_method, palette, node, rgb); - const int r2 = colormap_nearest_bruteforce(palette, rgb); + const uint8_t argb[] = {0xff, r, g, b}; + const int r1 = COLORMAP_NEAREST(search_method, palette, node, argb, trans_thresh); + const int r2 = colormap_nearest_bruteforce(palette, argb, trans_thresh); if (r1 != r2) { const uint32_t c1 = palette[r1]; const uint32_t c2 = palette[r2]; - const uint8_t palrgb1[] = { c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff }; - const uint8_t palrgb2[] = { c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff }; - const int d1 = diff(palrgb1, rgb); - const int d2 = diff(palrgb2, rgb); + const uint8_t palargb1[] = { 0xff, c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff }; + const uint8_t palargb2[] = { 0xff, c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff }; + const int d1 = diff(palargb1, argb, trans_thresh); + const int d2 = diff(palargb2, argb, trans_thresh); if (d1 != d2) { av_log(NULL, AV_LOG_ERROR, "/!\\ %02X%02X%02X: %d ! %d (%06"PRIX32" ! %06"PRIX32") / dist: %d ! %d\n", @@ -584,17 +602,19 @@ static int cmp_##name(const void *pa, const void *pb) \ { \ const struct color *a = pa; \ const struct color *b = pb; \ - return (a->value >> (8 * (2 - (pos))) & 0xff) \ - - (b->value >> (8 * (2 - (pos))) & 0xff); \ + return (a->value >> (8 * (3 - (pos))) & 0xff) \ + - (b->value >> (8 * (3 - (pos))) & 0xff); \ } -DECLARE_CMP_FUNC(r, 0) -DECLARE_CMP_FUNC(g, 1) -DECLARE_CMP_FUNC(b, 2) +DECLARE_CMP_FUNC(a, 0) +DECLARE_CMP_FUNC(r, 1) +DECLARE_CMP_FUNC(g, 2) +DECLARE_CMP_FUNC(b, 3) -static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b}; +static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b}; static int get_next_color(const uint8_t *color_used, const uint32_t *palette, + const int trans_thresh, int *component, const struct color_rect *box) { int wr, wg, wb; @@ -609,11 +629,16 @@ static int get_next_color(const uint8_t *color_used, const uint32_t *palette, for (i = 0; i < AVPALETTE_COUNT; i++) { const uint32_t c = palette[i]; + const uint8_t a = c >> 24 & 0xff; const uint8_t r = c >> 16 & 0xff; const uint8_t g = c >> 8 & 0xff; const uint8_t b = c & 0xff; - if (color_used[i] || + if (a < trans_thresh) { + continue; + } + + if (color_used[i] || (a != 0xff) || r < box->min[0] || g < box->min[1] || b < box->min[2] || r > box->max[0] || g > box->max[1] || b > box->max[2]) continue; @@ -639,9 +664,9 @@ static int get_next_color(const uint8_t *color_used, const uint32_t *palette, wr = ranges.max[0] - ranges.min[0]; wg = ranges.max[1] - ranges.min[1]; wb = ranges.max[2] - ranges.min[2]; - if (wr >= wg && wr >= wb) longest = 0; - if (wg >= wr && wg >= wb) longest = 1; - if (wb >= wr && wb >= wg) longest = 2; + if (wr >= wg && wr >= wb) longest = 1; + if (wg >= wr && wg >= wb) longest = 2; + if (wb >= wr && wb >= wg) longest = 3; cmpf = cmp_funcs[longest]; *component = longest; @@ -655,6 +680,7 @@ static int colormap_insert(struct color_node *map, uint8_t *color_used, int *nb_used, const uint32_t *palette, + const int trans_thresh, const struct color_rect *box) { uint32_t c; @@ -662,7 +688,7 @@ static int colormap_insert(struct color_node *map, int node_left_id = -1, node_right_id = -1; struct color_node *node; struct color_rect box1, box2; - const int pal_id = get_next_color(color_used, palette, &component, box); + const int pal_id = get_next_color(color_used, palette, trans_thresh, &component, box); if (pal_id < 0) return -1; @@ -673,21 +699,22 @@ static int colormap_insert(struct color_node *map, node = &map[cur_id]; node->split = component; node->palette_id = pal_id; - node->val[0] = c>>16 & 0xff; - node->val[1] = c>> 8 & 0xff; - node->val[2] = c & 0xff; + node->val[0] = c>>24 & 0xff; + node->val[1] = c>>16 & 0xff; + node->val[2] = c>> 8 & 0xff; + node->val[3] = c & 0xff; color_used[pal_id] = 1; /* get the two boxes this node creates */ box1 = box2 = *box; - box1.max[component] = node->val[component]; - box2.min[component] = node->val[component] + 1; + box1.max[component-1] = node->val[component]; + box2.min[component-1] = node->val[component] + 1; - node_left_id = colormap_insert(map, color_used, nb_used, palette, &box1); + node_left_id = colormap_insert(map, color_used, nb_used, palette, trans_thresh, &box1); - if (box2.min[component] <= box2.max[component]) - node_right_id = colormap_insert(map, color_used, nb_used, palette, &box2); + if (box2.min[component-1] <= box2.max[component-1]) + node_right_id = colormap_insert(map, color_used, nb_used, palette, trans_thresh, &box2); node->left_id = node_left_id; node->right_id = node_right_id; @@ -711,6 +738,16 @@ static void load_colormap(PaletteUseContext *s) /* disable transparent colors and dups */ qsort(s->palette, AVPALETTE_COUNT, sizeof(*s->palette), cmp_pal_entry); + // update transparency index: + if (s->transparency_index >= 0) { + for (i = 0; i < AVPALETTE_COUNT; i++) { + if ((s->palette[i]>>24 & 0xff) == 0) { + s->transparency_index = i; // we are assuming at most one transparent color in palette + break; + } + } + } + for (i = 0; i < AVPALETTE_COUNT; i++) { const uint32_t c = s->palette[i]; if (i != 0 && c == last_color) { @@ -718,7 +755,7 @@ static void load_colormap(PaletteUseContext *s) continue; } last_color = c; - if ((c & 0xff000000) != 0xff000000) { + if (c >> 24 < s->trans_thresh) { color_used[i] = 1; // ignore transparent color(s) continue; } @@ -727,13 +764,13 @@ static void load_colormap(PaletteUseContext *s) box.min[0] = box.min[1] = box.min[2] = 0x00; box.max[0] = box.max[1] = box.max[2] = 0xff; - colormap_insert(s->map, color_used, &nb_used, s->palette, &box); + colormap_insert(s->map, color_used, &nb_used, s->palette, s->trans_thresh, &box); if (s->dot_filename) disp_tree(s->map, s->dot_filename); if (s->debug_accuracy) { - if (!debug_accuracy(s->map, s->palette, s->color_search_method)) + if (!debug_accuracy(s->map, s->palette, s->trans_thresh, s->color_search_method)) av_log(NULL, AV_LOG_INFO, "Accuracy check passed\n"); } } @@ -754,9 +791,9 @@ static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1, for (x = 0; x < in1->width; x++) { const uint32_t c1 = src1[x]; const uint32_t c2 = palette[src2[x]]; - const uint8_t rgb1[] = {c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff}; - const uint8_t rgb2[] = {c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff}; - mean_err += diff(rgb1, rgb2); + const uint8_t argb1[] = {0xff, c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff}; + const uint8_t argb2[] = {0xff, c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff}; + mean_err += diff(argb1, argb2, s->trans_thresh); } src1 += src1_linesize; src2 += src2_linesize; @@ -857,9 +894,9 @@ static void set_processing_window(enum diff_mode diff_mode, *hp = height; } -static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in) +static int apply_palette(AVFilterLink *inlink, AVFrame *in, AVFrame **outf) { - int x, y, w, h; + int x, y, w, h, ret; AVFilterContext *ctx = inlink->dst; PaletteUseContext *s = ctx->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; @@ -867,7 +904,8 @@ static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in) AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { av_frame_free(&in); - return NULL; + *outf = NULL; + return AVERROR(ENOMEM); } av_frame_copy_props(out, in); @@ -881,21 +919,25 @@ static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in) av_frame_make_writable(s->last_in) < 0) { av_frame_free(&in); av_frame_free(&out); - return NULL; + *outf = NULL; + return AVERROR(ENOMEM); } ff_dlog(ctx, "%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n", w, h, x, y, x+w, y+h, in->width, in->height); - if (s->set_frame(s, out, in, x, y, w, h) < 0) { + ret = s->set_frame(s, out, in, x, y, w, h); + if (ret < 0) { av_frame_free(&out); - return NULL; + *outf = NULL; + return ret; } memcpy(out->data[1], s->palette, AVPALETTE_SIZE); if (s->calc_mean_err) debug_mean_error(s, in, out, inlink->frame_count_out); av_frame_free(&in); - return out; + *outf = out; + return 0; } static int config_output(AVFilterLink *outlink) @@ -941,6 +983,8 @@ static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame) const uint32_t *p = (const uint32_t *)palette_frame->data[0]; const int p_linesize = palette_frame->linesize[0] >> 2; + s->transparency_index = -1; + if (s->new) { memset(s->palette, 0, sizeof(s->palette)); memset(s->map, 0, sizeof(s->map)); @@ -951,8 +995,13 @@ static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame) i = 0; for (y = 0; y < palette_frame->height; y++) { - for (x = 0; x < palette_frame->width; x++) - s->palette[i++] = p[x]; + for (x = 0; x < palette_frame->width; x++) { + s->palette[i] = p[x]; + if (p[x]>>24 < s->trans_thresh) { + s->transparency_index = i; // we are assuming at most one transparent color in palette + } + i++; + } p += p_linesize; } @@ -967,7 +1016,7 @@ static int load_apply_palette(FFFrameSync *fs) AVFilterContext *ctx = fs->parent; AVFilterLink *inlink = ctx->inputs[0]; PaletteUseContext *s = ctx->priv; - AVFrame *master, *second, *out; + AVFrame *master, *second, *out = NULL; int ret; // writable for error diffusal dithering @@ -981,12 +1030,13 @@ static int load_apply_palette(FFFrameSync *fs) if (!s->palette_loaded) { load_palette(s, second); } - out = apply_palette(inlink, master); + ret = apply_palette(inlink, master, &out); + if (ret < 0) + goto error; return ff_filter_frame(ctx->outputs[0], out); error: av_frame_free(&master); - av_frame_free(&second); return ret; } diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c index 5120adc47..df4f26578 100644 --- a/libavfilter/vf_premultiply.c +++ b/libavfilter/vf_premultiply.c @@ -607,9 +607,10 @@ static int activate(AVFilterContext *ctx) int64_t pts; if ((ret = ff_inlink_consume_frame(ctx->inputs[0], &frame)) > 0) { - if ((ret = filter_frame(ctx, &out, frame, frame)) < 0) - return ret; + ret = filter_frame(ctx, &out, frame, frame); av_frame_free(&frame); + if (ret < 0) + return ret; ret = ff_filter_frame(ctx->outputs[0], out); } if (ret < 0) { diff --git a/libavfilter/vf_program_opencl.c b/libavfilter/vf_program_opencl.c new file mode 100644 index 000000000..4ee966823 --- /dev/null +++ b/libavfilter/vf_program_opencl.c @@ -0,0 +1,444 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/avstring.h" +#include "libavutil/buffer.h" +#include "libavutil/common.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_opencl.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/opt.h" + +#include "avfilter.h" +#include "framesync.h" +#include "internal.h" +#include "opencl.h" +#include "video.h" + +typedef struct ProgramOpenCLContext { + OpenCLFilterContext ocf; + + int loaded; + cl_uint index; + cl_kernel kernel; + cl_command_queue command_queue; + + FFFrameSync fs; + AVFrame **frames; + + const char *source_file; + const char *kernel_name; + int nb_inputs; + int width, height; + enum AVPixelFormat source_format; + AVRational source_rate; +} ProgramOpenCLContext; + +static int program_opencl_load(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program_from_file(avctx, ctx->source_file); + if (err < 0) + return err; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + + ctx->kernel = clCreateKernel(ctx->ocf.program, ctx->kernel_name, &cle); + if (!ctx->kernel) { + if (cle == CL_INVALID_KERNEL_NAME) { + av_log(avctx, AV_LOG_ERROR, "Kernel function '%s' not found in " + "program.\n", ctx->kernel_name); + } else { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + } + return AVERROR(EIO); + } + + ctx->loaded = 1; + return 0; +} + +static int program_opencl_run(AVFilterContext *avctx) +{ + AVFilterLink *outlink = avctx->outputs[0]; + ProgramOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst; + int err, input, plane; + + if (!ctx->loaded) { + err = program_opencl_load(avctx); + if (err < 0) + return err; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (plane = 0; plane < FF_ARRAY_ELEMS(output->data); plane++) { + dst = (cl_mem)output->data[plane]; + if (!dst) + break; + + cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_uint), &ctx->index); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "index argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + + for (input = 0; input < ctx->nb_inputs; input++) { + av_assert0(ctx->frames[input]); + + src = (cl_mem)ctx->frames[input]->data[plane]; + av_assert0(src); + + cle = clSetKernelArg(ctx->kernel, 2 + input, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument %d: %d.\n", input, cle); + err = AVERROR_UNKNOWN; + goto fail; + } + } + + cle = clGetImageInfo(dst, CL_IMAGE_WIDTH, sizeof(size_t), + &global_work[0], NULL); + cle = clGetImageInfo(dst, CL_IMAGE_HEIGHT, sizeof(size_t), + &global_work[1], NULL); + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%zux%zu).\n", plane, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + if (ctx->nb_inputs > 0) { + err = av_frame_copy_props(output, ctx->frames[0]); + if (err < 0) + goto fail; + } else { + output->pts = ctx->index; + } + ++ctx->index; + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&output); + return err; +} + +static int program_opencl_request_frame(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + + return program_opencl_run(avctx); +} + +static int program_opencl_filter(FFFrameSync *fs) +{ + AVFilterContext *avctx = fs->parent; + ProgramOpenCLContext *ctx = avctx->priv; + int err, i; + + for (i = 0; i < ctx->nb_inputs; i++) { + err = ff_framesync_get_frame(&ctx->fs, i, &ctx->frames[i], 0); + if (err < 0) + return err; + } + + return program_opencl_run(avctx); +} + +static int program_opencl_activate(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + + av_assert0(ctx->nb_inputs > 0); + + return ff_framesync_activate(&ctx->fs); +} + +static int program_opencl_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + ProgramOpenCLContext *ctx = avctx->priv; + int err; + + err = ff_opencl_filter_config_output(outlink); + if (err < 0) + return err; + + if (ctx->nb_inputs > 0) { + FFFrameSyncIn *in; + int i; + + err = ff_framesync_init(&ctx->fs, avctx, ctx->nb_inputs); + if (err < 0) + return err; + + ctx->fs.opaque = ctx; + ctx->fs.on_event = &program_opencl_filter; + + in = ctx->fs.in; + for (i = 0; i < ctx->nb_inputs; i++) { + const AVFilterLink *inlink = avctx->inputs[i]; + + in[i].time_base = inlink->time_base; + in[i].sync = 1; + in[i].before = EXT_STOP; + in[i].after = EXT_INFINITY; + } + + err = ff_framesync_configure(&ctx->fs); + if (err < 0) + return err; + + } else { + outlink->time_base = av_inv_q(ctx->source_rate); + } + + return 0; +} + +static av_cold int program_opencl_init(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + int err; + + ff_opencl_filter_init(avctx); + + ctx->ocf.output_width = ctx->width; + ctx->ocf.output_height = ctx->height; + + if (!strcmp(avctx->filter->name, "openclsrc")) { + if (!ctx->ocf.output_width || !ctx->ocf.output_height) { + av_log(avctx, AV_LOG_ERROR, "OpenCL source requires output " + "dimensions to be specified.\n"); + return AVERROR(EINVAL); + } + + ctx->nb_inputs = 0; + ctx->ocf.output_format = ctx->source_format; + } else { + int i; + + ctx->frames = av_mallocz_array(ctx->nb_inputs, + sizeof(*ctx->frames)); + if (!ctx->frames) + return AVERROR(ENOMEM); + + for (i = 0; i < ctx->nb_inputs; i++) { + AVFilterPad input; + memset(&input, 0, sizeof(input)); + + input.type = AVMEDIA_TYPE_VIDEO; + input.name = av_asprintf("input%d", i); + if (!input.name) + return AVERROR(ENOMEM); + + input.config_props = &ff_opencl_filter_config_input; + + err = ff_insert_inpad(avctx, i, &input); + if (err < 0) { + av_freep(&input.name); + return err; + } + } + } + + return 0; +} + +static av_cold void program_opencl_uninit(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + cl_int cle; + int i; + + if (ctx->nb_inputs > 0) { + ff_framesync_uninit(&ctx->fs); + + av_freep(&ctx->frames); + for (i = 0; i < avctx->nb_inputs; i++) + av_freep(&avctx->input_pads[i].name); + } + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(ProgramOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) + +#if CONFIG_PROGRAM_OPENCL_FILTER + +static const AVOption program_opencl_options[] = { + { "source", "OpenCL program source file", OFFSET(source_file), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { "kernel", "Kernel name in program", OFFSET(kernel_name), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + + { "inputs", "Number of inputs", OFFSET(nb_inputs), + AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS }, + + { "size", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + { "s", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + + { NULL }, +}; + +FRAMESYNC_DEFINE_CLASS(program_opencl, ProgramOpenCLContext, fs); + +static const AVFilterPad program_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &program_opencl_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_program_opencl = { + .name = "program_opencl", + .description = NULL_IF_CONFIG_SMALL("Filter video using an OpenCL program"), + .priv_size = sizeof(ProgramOpenCLContext), + .priv_class = &program_opencl_class, + .preinit = &program_opencl_framesync_preinit, + .init = &program_opencl_init, + .uninit = &program_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .activate = &program_opencl_activate, + .inputs = NULL, + .outputs = program_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif + +#if CONFIG_OPENCLSRC_FILTER + +static const AVOption openclsrc_options[] = { + { "source", "OpenCL program source file", OFFSET(source_file), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { "kernel", "Kernel name in program", OFFSET(kernel_name), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + + { "size", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + { "s", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + + { "format", "Video format", OFFSET(source_format), + AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, -1, INT_MAX, FLAGS }, + + { "rate", "Video frame rate", OFFSET(source_rate), + AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, FLAGS }, + { "r", "Video frame rate", OFFSET(source_rate), + AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, FLAGS }, + + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(openclsrc); + +static const AVFilterPad openclsrc_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &program_opencl_config_output, + .request_frame = &program_opencl_request_frame, + }, + { NULL } +}; + +AVFilter ff_vsrc_openclsrc = { + .name = "openclsrc", + .description = NULL_IF_CONFIG_SMALL("Generate video using an OpenCL program"), + .priv_size = sizeof(ProgramOpenCLContext), + .priv_class = &openclsrc_class, + .init = &program_opencl_init, + .uninit = &program_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = NULL, + .outputs = openclsrc_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif diff --git a/libavfilter/vf_pseudocolor.c b/libavfilter/vf_pseudocolor.c index f8f537275..2e7a3a95f 100644 --- a/libavfilter/vf_pseudocolor.c +++ b/libavfilter/vf_pseudocolor.c @@ -94,7 +94,7 @@ static const AVOption pseudocolor_options[] = { }; static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GBRP, @@ -114,7 +114,10 @@ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; @@ -531,11 +534,17 @@ static int config_input(AVFilterLink *inlink) case AV_PIX_FMT_YUV444P14: case AV_PIX_FMT_YUV444P16: case AV_PIX_FMT_YUVA444P16: + case AV_PIX_FMT_GBRP9: case AV_PIX_FMT_GBRP10: - case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRP14: case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRAP12: case AV_PIX_FMT_GBRAP16: + case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: case AV_PIX_FMT_GRAY16: s->filter[0] = s->filter[1] = s->filter[2] = s->filter[3] = pseudocolor_filter_16; break; diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c index 493a501a7..153d694b7 100644 --- a/libavfilter/vf_psnr.c +++ b/libavfilter/vf_psnr.c @@ -270,7 +270,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, - AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 3329c1234..9f45032e8 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -362,6 +362,7 @@ static int config_props_ref(AVFilterLink *outlink) outlink->h = inlink->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->time_base = inlink->time_base; + outlink->frame_rate = inlink->frame_rate; return 0; } @@ -577,7 +578,9 @@ static const AVOption scale_options[] = { { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" }, { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" }, { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, "range" }, + { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, "range" }, { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, + { "limited",NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, diff --git a/libavfilter/vf_setparams.c b/libavfilter/vf_setparams.c new file mode 100644 index 000000000..8427f98ba --- /dev/null +++ b/libavfilter/vf_setparams.c @@ -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 + */ + +#include "libavutil/pixfmt.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "internal.h" +#include "video.h" + +typedef struct SetParamsContext { + const AVClass *class; + int color_range; +} SetParamsContext; + +#define OFFSET(x) offsetof(SetParamsContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption setrange_options[] = { + {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=-1},-1, AVCOL_RANGE_NB-1, FLAGS, "range"}, + {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "range"}, + {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, + {"limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {"pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(setrange); + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + SetParamsContext *s = ctx->priv; + + if (s->color_range >= 0) + frame->color_range = s->color_range; + return ff_filter_frame(ctx->outputs[0], frame); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_setrange = { + .name = "setrange", + .description = NULL_IF_CONFIG_SMALL("Force color range for the output video frame."), + .priv_size = sizeof(SetParamsContext), + .priv_class = &setrange_class, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c index 14b8aa4af..d1d1415c0 100644 --- a/libavfilter/vf_showinfo.c +++ b/libavfilter/vf_showinfo.c @@ -29,6 +29,7 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/pixdesc.h" +#include "libavutil/spherical.h" #include "libavutil/stereo3d.h" #include "libavutil/timestamp.h" @@ -36,6 +37,45 @@ #include "internal.h" #include "video.h" +static void dump_spherical(AVFilterContext *ctx, AVFrame *frame, AVFrameSideData *sd) +{ + AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; + double yaw, pitch, roll; + + av_log(ctx, AV_LOG_INFO, "spherical information: "); + if (sd->size < sizeof(*spherical)) { + av_log(ctx, AV_LOG_INFO, "invalid data"); + return; + } + + if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR) + av_log(ctx, AV_LOG_INFO, "equirectangular "); + else if (spherical->projection == AV_SPHERICAL_CUBEMAP) + av_log(ctx, AV_LOG_INFO, "cubemap "); + else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) + av_log(ctx, AV_LOG_INFO, "tiled equirectangular "); + else { + av_log(ctx, AV_LOG_WARNING, "unknown"); + return; + } + + yaw = ((double)spherical->yaw) / (1 << 16); + pitch = ((double)spherical->pitch) / (1 << 16); + roll = ((double)spherical->roll) / (1 << 16); + av_log(ctx, AV_LOG_INFO, "(%f/%f/%f) ", yaw, pitch, roll); + + if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { + size_t l, t, r, b; + av_spherical_tile_bounds(spherical, frame->width, frame->height, + &l, &t, &r, &b); + av_log(ctx, AV_LOG_INFO, + "[%"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER"] ", + l, t, r, b); + } else if (spherical->projection == AV_SPHERICAL_CUBEMAP) { + av_log(ctx, AV_LOG_INFO, "[pad %"PRIu32"] ", spherical->padding); + } +} + static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd) { AVStereo3D *stereo; @@ -48,19 +88,7 @@ static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd) stereo = (AVStereo3D *)sd->data; - av_log(ctx, AV_LOG_INFO, "type - "); - switch (stereo->type) { - case AV_STEREO3D_2D: av_log(ctx, AV_LOG_INFO, "2D"); break; - case AV_STEREO3D_SIDEBYSIDE: av_log(ctx, AV_LOG_INFO, "side by side"); break; - case AV_STEREO3D_TOPBOTTOM: av_log(ctx, AV_LOG_INFO, "top and bottom"); break; - case AV_STEREO3D_FRAMESEQUENCE: av_log(ctx, AV_LOG_INFO, "frame alternate"); break; - case AV_STEREO3D_CHECKERBOARD: av_log(ctx, AV_LOG_INFO, "checkerboard"); break; - case AV_STEREO3D_LINES: av_log(ctx, AV_LOG_INFO, "interleaved lines"); break; - case AV_STEREO3D_COLUMNS: av_log(ctx, AV_LOG_INFO, "interleaved columns"); break; - case AV_STEREO3D_SIDEBYSIDE_QUINCUNX: av_log(ctx, AV_LOG_INFO, "side by side " - "(quincunx subsampling)"); break; - default: av_log(ctx, AV_LOG_WARNING, "unknown"); break; - } + av_log(ctx, AV_LOG_INFO, "type - %s", av_stereo3d_type_name(stereo->type)); if (stereo->flags & AV_STEREO3D_FLAG_INVERT) av_log(ctx, AV_LOG_INFO, " (inverted)"); @@ -140,6 +168,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case AV_FRAME_DATA_A53_CC: av_log(ctx, AV_LOG_INFO, "A/53 closed captions (%d bytes)", sd->size); break; + case AV_FRAME_DATA_SPHERICAL: + dump_spherical(ctx, frame, sd); + break; case AV_FRAME_DATA_STEREO3D: dump_stereo3d(ctx, sd); break; diff --git a/libavfilter/vf_stack.c b/libavfilter/vf_stack.c index 246730215..b2b8c6804 100644 --- a/libavfilter/vf_stack.c +++ b/libavfilter/vf_stack.c @@ -105,6 +105,7 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); + out->sample_aspect_ratio = outlink->sample_aspect_ratio; for (i = 0; i < s->nb_inputs; i++) { AVFilterLink *inlink = ctx->inputs[i]; @@ -147,6 +148,7 @@ static int config_output(AVFilterLink *outlink) StackContext *s = ctx->priv; AVRational time_base = ctx->inputs[0]->time_base; AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVRational sar = ctx->inputs[0]->sample_aspect_ratio; int height = ctx->inputs[0]->h; int width = ctx->inputs[0]->w; FFFrameSyncIn *in; @@ -179,6 +181,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = height; outlink->time_base = time_base; outlink->frame_rate = frame_rate; + outlink->sample_aspect_ratio = sar; if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) return ret; diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c index 66a564699..a7b02461f 100644 --- a/libavfilter/vf_subtitles.c +++ b/libavfilter/vf_subtitles.c @@ -413,7 +413,7 @@ static av_cold int init_subtitles(AVFilterContext *ctx) * * That API is old and needs to be reworked to match behaviour with A/V. */ - av_codec_set_pkt_timebase(dec_ctx, st->time_base); + dec_ctx->pkt_timebase = st->time_base; ret = avcodec_open2(dec_ctx, NULL, &codec_opts); if (ret < 0) diff --git a/libavfilter/vf_threshold.c b/libavfilter/vf_threshold.c index 88f6ef28d..58b5d1483 100644 --- a/libavfilter/vf_threshold.c +++ b/libavfilter/vf_threshold.c @@ -31,27 +31,7 @@ #include "framesync.h" #include "internal.h" #include "video.h" - -typedef struct ThresholdContext { - const AVClass *class; - - int planes; - int bpc; - - int nb_planes; - int width[4], height[4]; - - void (*threshold)(const uint8_t *in, const uint8_t *threshold, - const uint8_t *min, const uint8_t *max, - uint8_t *out, - ptrdiff_t ilinesize, ptrdiff_t tlinesize, - ptrdiff_t flinesize, ptrdiff_t slinesize, - ptrdiff_t olinesize, - int w, int h); - - AVFrame *frames[4]; - FFFrameSync fs; -} ThresholdContext; +#include "threshold.h" #define OFFSET(x) offsetof(ThresholdContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -155,7 +135,7 @@ static void threshold8(const uint8_t *in, const uint8_t *threshold, in += ilinesize; threshold += tlinesize; min += flinesize; - max += flinesize; + max += slinesize; out += olinesize; } } @@ -183,7 +163,7 @@ static void threshold16(const uint8_t *iin, const uint8_t *tthreshold, in += ilinesize / 2; threshold += tlinesize / 2; min += flinesize / 2; - max += flinesize / 2; + max += slinesize / 2; out += olinesize / 2; } } @@ -203,8 +183,16 @@ static int config_input(AVFilterLink *inlink) s->height[0] = s->height[3] = inlink->h; s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, hsub); s->width[0] = s->width[3] = inlink->w; + s->depth = desc->comp[0].depth; - if (desc->comp[0].depth == 8) { + ff_threshold_init(s); + + return 0; +} + +void ff_threshold_init(ThresholdContext *s) +{ + if (s->depth == 8) { s->threshold = threshold8; s->bpc = 1; } else { @@ -212,7 +200,8 @@ static int config_input(AVFilterLink *inlink) s->bpc = 2; } - return 0; + if (ARCH_X86) + ff_threshold_init_x86(s); } static int config_output(AVFilterLink *outlink) diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c index 87e0b940c..439689a14 100644 --- a/libavfilter/vf_tile.c +++ b/libavfilter/vf_tile.c @@ -23,6 +23,7 @@ * tile video filter */ +#include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" @@ -36,16 +37,17 @@ typedef struct TileContext { unsigned w, h; unsigned margin; unsigned padding; + unsigned overlap; + unsigned init_padding; unsigned current; unsigned nb_frames; FFDrawContext draw; FFDrawColor blank; AVFrame *out_ref; + AVFrame *prev_out_ref; uint8_t rgba_color[4]; } TileContext; -#define REASONABLE_SIZE 1024 - #define OFFSET(x) offsetof(TileContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -59,6 +61,10 @@ static const AVOption tile_options[] = { { "padding", "set inner border thickness in pixels", OFFSET(padding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1024, FLAGS }, { "color", "set the color of the unused area", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS }, + { "overlap", "set how many frames to overlap for each render", OFFSET(overlap), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, + { "init_padding", " set how many frames to initially pad", OFFSET(init_padding), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, { NULL } }; @@ -68,12 +74,21 @@ static av_cold int init(AVFilterContext *ctx) { TileContext *tile = ctx->priv; - if (tile->w > REASONABLE_SIZE || tile->h > REASONABLE_SIZE) { + if (tile->w > UINT_MAX / tile->h) { av_log(ctx, AV_LOG_ERROR, "Tile size %ux%u is insane.\n", tile->w, tile->h); return AVERROR(EINVAL); } + if (tile->padding) { + if ((tile->w - 1 > (UINT32_MAX - 2 * tile->margin) / tile->padding) || + (tile->h - 1 > (UINT32_MAX - 2 * tile->margin) / tile->padding)) { + av_log(ctx, AV_LOG_ERROR, "Combination of Tile size %ux%u, padding %d and margin %d overflows.\n", + tile->w, tile->h, tile->padding, tile->margin); + return AVERROR(EINVAL); + } + } + if (tile->nb_frames == 0) { tile->nb_frames = tile->w * tile->h; } else if (tile->nb_frames > tile->w * tile->h) { @@ -82,6 +97,17 @@ static av_cold int init(AVFilterContext *ctx) return AVERROR(EINVAL); } + if (tile->overlap >= tile->nb_frames) { + av_log(ctx, AV_LOG_WARNING, "overlap must be less than %d\n", tile->nb_frames); + tile->overlap = tile->nb_frames - 1; + } + + if (tile->init_padding >= tile->nb_frames) { + av_log(ctx, AV_LOG_WARNING, "init_padding must be less than %d\n", tile->nb_frames); + } else { + tile->current = tile->init_padding; + } + return 0; } @@ -112,19 +138,19 @@ static int config_props(AVFilterLink *outlink) outlink->h = tile->h * inlink->h + total_margin_h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->frame_rate = av_mul_q(inlink->frame_rate, - av_make_q(1, tile->nb_frames)); + av_make_q(1, tile->nb_frames - tile->overlap)); ff_draw_init(&tile->draw, inlink->format, 0); ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color); return 0; } -static void get_current_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y) +static void get_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y, unsigned current) { TileContext *tile = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - const unsigned tx = tile->current % tile->w; - const unsigned ty = tile->current / tile->w; + const unsigned tx = current % tile->w; + const unsigned ty = current / tile->w; *x = tile->margin + (inlink->w + tile->padding) * tx; *y = tile->margin + (inlink->h + tile->padding) * ty; @@ -136,12 +162,13 @@ static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf) AVFilterLink *inlink = ctx->inputs[0]; unsigned x0, y0; - get_current_tile_pos(ctx, &x0, &y0); + get_tile_pos(ctx, &x0, &y0, tile->current); ff_fill_rectangle(&tile->draw, &tile->blank, out_buf->data, out_buf->linesize, x0, y0, inlink->w, inlink->h); tile->current++; } + static int end_last_frame(AVFilterContext *ctx) { TileContext *tile = ctx->priv; @@ -151,8 +178,13 @@ static int end_last_frame(AVFilterContext *ctx) while (tile->current < tile->nb_frames) draw_blank_frame(ctx, out_buf); + tile->current = tile->overlap; + if (tile->current) { + av_frame_free(&tile->prev_out_ref); + tile->prev_out_ref = av_frame_clone(out_buf); + } ret = ff_filter_frame(outlink, out_buf); - tile->current = 0; + tile->out_ref = NULL; return ret; } @@ -167,7 +199,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) AVFilterLink *outlink = ctx->outputs[0]; unsigned x0, y0; - if (!tile->current) { + if (!tile->out_ref) { tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!tile->out_ref) { av_frame_free(&picref); @@ -178,14 +210,29 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) tile->out_ref->height = outlink->h; /* fill surface once for margin/padding */ - if (tile->margin || tile->padding) + if (tile->margin || tile->padding || tile->init_padding) ff_fill_rectangle(&tile->draw, &tile->blank, tile->out_ref->data, tile->out_ref->linesize, 0, 0, outlink->w, outlink->h); + tile->init_padding = 0; } - get_current_tile_pos(ctx, &x0, &y0); + if (tile->prev_out_ref) { + unsigned x1, y1, i; + + for (i = tile->nb_frames - tile->overlap; i < tile->nb_frames; i++) { + get_tile_pos(ctx, &x1, &y1, i); + get_tile_pos(ctx, &x0, &y0, i - (tile->nb_frames - tile->overlap)); + ff_copy_rectangle2(&tile->draw, + tile->out_ref->data, tile->out_ref->linesize, + tile->prev_out_ref->data, tile->prev_out_ref->linesize, + x0, y0, x1, y1, inlink->w, inlink->h); + + } + } + + get_tile_pos(ctx, &x0, &y0, tile->current); ff_copy_rectangle2(&tile->draw, tile->out_ref->data, tile->out_ref->linesize, picref->data, picref->linesize, @@ -206,11 +253,18 @@ static int request_frame(AVFilterLink *outlink) int r; r = ff_request_frame(inlink); - if (r == AVERROR_EOF && tile->current) + if (r == AVERROR_EOF && tile->current && tile->out_ref) r = end_last_frame(ctx); return r; } +static av_cold void uninit(AVFilterContext *ctx) +{ + TileContext *tile = ctx->priv; + + av_frame_free(&tile->prev_out_ref); +} + static const AVFilterPad tile_inputs[] = { { .name = "default", @@ -234,6 +288,7 @@ AVFilter ff_vf_tile = { .name = "tile", .description = NULL_IF_CONFIG_SMALL("Tile several successive frames together."), .init = init, + .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(TileContext), .inputs = tile_inputs, diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c index 438ff6d8f..41ccc5694 100644 --- a/libavfilter/vf_unsharp.c +++ b/libavfilter/vf_unsharp.c @@ -46,7 +46,6 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "unsharp.h" -#include "unsharp_opencl.h" static void apply_unsharp( uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, @@ -134,10 +133,8 @@ static void set_filter_param(UnsharpFilterParam *fp, int msize_x, int msize_y, f static av_cold int init(AVFilterContext *ctx) { - int ret = 0; UnsharpContext *s = ctx->priv; - set_filter_param(&s->luma, s->lmsize_x, s->lmsize_y, s->lamount); set_filter_param(&s->chroma, s->cmsize_x, s->cmsize_y, s->camount); @@ -146,16 +143,6 @@ static av_cold int init(AVFilterContext *ctx) return AVERROR(EINVAL); } s->apply_unsharp = apply_unsharp_c; - if (!CONFIG_OPENCL && s->opencl) { - av_log(ctx, AV_LOG_ERROR, "OpenCL support was not enabled in this build, cannot be selected\n"); - return AVERROR(EINVAL); - } - if (CONFIG_OPENCL && s->opencl) { - s->apply_unsharp = ff_opencl_apply_unsharp; - ret = ff_opencl_unsharp_init(ctx); - if (ret < 0) - return ret; - } return 0; } @@ -227,10 +214,6 @@ static av_cold void uninit(AVFilterContext *ctx) { UnsharpContext *s = ctx->priv; - if (CONFIG_OPENCL && s->opencl) { - ff_opencl_unsharp_uninit(ctx); - } - free_filter_param(&s->luma); free_filter_param(&s->chroma); } @@ -248,14 +231,9 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) return AVERROR(ENOMEM); } av_frame_copy_props(out, in); - if (CONFIG_OPENCL && s->opencl) { - ret = ff_opencl_unsharp_process_inout_buf(link->dst, in, out); - if (ret < 0) - goto end; - } ret = s->apply_unsharp(link->dst, in, out); -end: + av_frame_free(&in); if (ret < 0) { @@ -282,7 +260,7 @@ static const AVOption unsharp_options[] = { { "cy", "set chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS }, { "chroma_amount", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS }, { "ca", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS }, - { "opencl", "use OpenCL filtering capabilities", OFFSET(opencl), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "opencl", "ignored", OFFSET(opencl), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { NULL } }; diff --git a/libavfilter/vf_unsharp_opencl.c b/libavfilter/vf_unsharp_opencl.c new file mode 100644 index 000000000..6a453c014 --- /dev/null +++ b/libavfilter/vf_unsharp_opencl.c @@ -0,0 +1,483 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +#define MAX_DIAMETER 23 + +typedef struct UnsharpOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + float luma_size_x; + float luma_size_y; + float luma_amount; + float chroma_size_x; + float chroma_size_y; + float chroma_amount; + + int global; + + int nb_planes; + struct { + float blur_x[MAX_DIAMETER]; + float blur_y[MAX_DIAMETER]; + + cl_mem matrix; + cl_mem coef_x; + cl_mem coef_y; + + cl_int size_x; + cl_int size_y; + cl_float amount; + cl_float threshold; + } plane[4]; +} UnsharpOpenCLContext; + + +static int unsharp_opencl_init(AVFilterContext *avctx) +{ + UnsharpOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_unsharp, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + // Use global kernel if mask size will be too big for the local store.. + ctx->global = (ctx->luma_size_x > 17.0f || + ctx->luma_size_y > 17.0f || + ctx->chroma_size_x > 17.0f || + ctx->chroma_size_y > 17.0f); + + ctx->kernel = clCreateKernel(ctx->ocf.program, + ctx->global ? "unsharp_global" + : "unsharp_local", &cle); + if (!ctx->kernel) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int unsharp_opencl_make_filter_params(AVFilterContext *avctx) +{ + UnsharpOpenCLContext *ctx = avctx->priv; + const AVPixFmtDescriptor *desc; + float *matrix; + double val, sum; + cl_int cle; + cl_mem buffer; + size_t matrix_bytes; + float diam_x, diam_y, amount; + int err, p, x, y, size_x, size_y; + + desc = av_pix_fmt_desc_get(ctx->ocf.output_format); + + ctx->nb_planes = 0; + for (p = 0; p < desc->nb_components; p++) + ctx->nb_planes = FFMAX(ctx->nb_planes, desc->comp[p].plane + 1); + + for (p = 0; p < ctx->nb_planes; p++) { + if (p == 0 || (desc->flags & AV_PIX_FMT_FLAG_RGB)) { + diam_x = ctx->luma_size_x; + diam_y = ctx->luma_size_y; + amount = ctx->luma_amount; + } else { + diam_x = ctx->chroma_size_x; + diam_y = ctx->chroma_size_y; + amount = ctx->chroma_amount; + } + size_x = (int)ceil(diam_x) | 1; + size_y = (int)ceil(diam_y) | 1; + matrix_bytes = size_x * size_y * sizeof(float); + + matrix = av_malloc(matrix_bytes); + if (!matrix) { + err = AVERROR(ENOMEM); + goto fail; + } + + sum = 0.0; + for (x = 0; x < size_x; x++) { + double dx = (double)(x - size_x / 2) / diam_x; + sum += ctx->plane[p].blur_x[x] = exp(-16.0 * (dx * dx)); + } + for (x = 0; x < size_x; x++) + ctx->plane[p].blur_x[x] /= sum; + + sum = 0.0; + for (y = 0; y < size_y; y++) { + double dy = (double)(y - size_y / 2) / diam_y; + sum += ctx->plane[p].blur_y[y] = exp(-16.0 * (dy * dy)); + } + for (y = 0; y < size_y; y++) + ctx->plane[p].blur_y[y] /= sum; + + for (y = 0; y < size_y; y++) { + for (x = 0; x < size_x; x++) { + val = ctx->plane[p].blur_x[x] * ctx->plane[p].blur_y[y]; + matrix[y * size_x + x] = val; + } + } + + if (ctx->global) { + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + matrix_bytes, matrix, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create matrix buffer: " + "%d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + ctx->plane[p].matrix = buffer; + } else { + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + sizeof(ctx->plane[p].blur_x), + ctx->plane[p].blur_x, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create x-coef buffer: " + "%d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + ctx->plane[p].coef_x = buffer; + + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + sizeof(ctx->plane[p].blur_y), + ctx->plane[p].blur_y, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create y-coef buffer: " + "%d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + ctx->plane[p].coef_y = buffer; + } + + av_freep(&matrix); + + ctx->plane[p].size_x = size_x; + ctx->plane[p].size_y = size_y; + ctx->plane[p].amount = amount; + } + + err = 0; +fail: + av_freep(&matrix); + return err; +} + +static int unsharp_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + UnsharpOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + size_t local_work[2]; + cl_mem src, dst; + int err, p; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = unsharp_opencl_init(avctx); + if (err < 0) + goto fail; + + err = unsharp_opencl_make_filter_params(avctx); + if (err < 0) + goto fail; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem)output->data[p]; + + if (!dst) + break; + + cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 2, sizeof(cl_int), &ctx->plane[p].size_x); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix size argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 3, sizeof(cl_int), &ctx->plane[p].size_y); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix size argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 4, sizeof(cl_float), &ctx->plane[p].amount); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "amount argument: %d.\n", cle); + goto fail; + } + if (ctx->global) { + cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_mem), &ctx->plane[p].matrix); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix argument: %d.\n", cle); + goto fail; + } + } else { + cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_mem), &ctx->plane[p].coef_x); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "x-coef argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 6, sizeof(cl_mem), &ctx->plane[p].coef_y); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "y-coef argument: %d.\n", cle); + goto fail; + } + } + + if (ctx->global) { + global_work[0] = output->width; + global_work[1] = output->height; + } else { + global_work[0] = FFALIGN(output->width, 16); + global_work[1] = FFALIGN(output->height, 16); + local_work[0] = 16; + local_work[1] = 16; + } + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, ctx->global ? NULL : local_work, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void unsharp_opencl_uninit(AVFilterContext *avctx) +{ + UnsharpOpenCLContext *ctx = avctx->priv; + cl_int cle; + int i; + + for (i = 0; i < ctx->nb_planes; i++) { + if (ctx->plane[i].matrix) + clReleaseMemObject(ctx->plane[i].matrix); + if (ctx->plane[i].coef_x) + clReleaseMemObject(ctx->plane[i].coef_x); + if (ctx->plane[i].coef_y) + clReleaseMemObject(ctx->plane[i].coef_y); + } + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(UnsharpOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption unsharp_opencl_options[] = { + { "luma_msize_x", "Set luma mask horizontal diameter (pixels)", + OFFSET(luma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "lx", "Set luma mask horizontal diameter (pixels)", + OFFSET(luma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "luma_msize_y", "Set luma mask vertical diameter (pixels)", + OFFSET(luma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "ly", "Set luma mask vertical diameter (pixels)", + OFFSET(luma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "luma_amount", "Set luma amount (multiplier)", + OFFSET(luma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 1.0 }, -10, 10, FLAGS }, + { "la", "Set luma amount (multiplier)", + OFFSET(luma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 1.0 }, -10, 10, FLAGS }, + + { "chroma_msize_x", "Set chroma mask horizontal diameter (pixels after subsampling)", + OFFSET(chroma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "cx", "Set chroma mask horizontal diameter (pixels after subsampling)", + OFFSET(chroma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "chroma_msize_y", "Set chroma mask vertical diameter (pixels after subsampling)", + OFFSET(chroma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "cy", "Set chroma mask vertical diameter (pixels after subsampling)", + OFFSET(chroma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "chroma_amount", "Set chroma amount (multiplier)", + OFFSET(chroma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 0.0 }, -10, 10, FLAGS }, + { "ca", "Set chroma amount (multiplier)", + OFFSET(chroma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 0.0 }, -10, 10, FLAGS }, + + { NULL } +}; + +AVFILTER_DEFINE_CLASS(unsharp_opencl); + +static const AVFilterPad unsharp_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &unsharp_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad unsharp_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_unsharp_opencl = { + .name = "unsharp_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply unsharp mask to input video"), + .priv_size = sizeof(UnsharpOpenCLContext), + .priv_class = &unsharp_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &unsharp_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = unsharp_opencl_inputs, + .outputs = unsharp_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c new file mode 100644 index 000000000..bd5fc3229 --- /dev/null +++ b/libavfilter/vf_vpp_qsv.c @@ -0,0 +1,406 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + ** Hardware accelerated common filters based on Intel Quick Sync Video VPP + **/ + +#include + +#include "libavutil/opt.h" +#include "libavutil/eval.h" +#include "libavutil/avassert.h" +#include "libavutil/pixdesc.h" + +#include "formats.h" +#include "internal.h" +#include "avfilter.h" +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" + +#include "qsvvpp.h" + +#define OFFSET(x) offsetof(VPPContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) + +/* number of video enhancement filters */ +#define ENH_FILTERS_COUNT (5) + +typedef struct VPPContext{ + const AVClass *class; + + QSVVPPContext *qsv; + + /* Video Enhancement Algorithms */ + mfxExtVPPDeinterlacing deinterlace_conf; + mfxExtVPPFrameRateConversion frc_conf; + mfxExtVPPDenoise denoise_conf; + mfxExtVPPDetail detail_conf; + mfxExtVPPProcAmp procamp_conf; + + int out_width; + int out_height; + + AVRational framerate; /* target framerate */ + int use_frc; /* use framerate conversion */ + int deinterlace; /* deinterlace mode : 0=off, 1=bob, 2=advanced */ + int denoise; /* Enable Denoise algorithm. Value [0, 100] */ + int detail; /* Enable Detail Enhancement algorithm. */ + /* Level is the optional, value [0, 100] */ + int use_crop; /* 1 = use crop; 0=none */ + int crop_w; + int crop_h; + int crop_x; + int crop_y; + + /* param for the procamp */ + int procamp; /* enable procamp */ + float hue; + float saturation; + float contrast; + float brightness; + + char *cx, *cy, *cw, *ch; + char *ow, *oh; +} VPPContext; + +static const AVOption options[] = { + { "deinterlace", "deinterlace mode: 0=off, 1=bob, 2=advanced", OFFSET(deinterlace), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MFX_DEINTERLACING_ADVANCED, .flags = FLAGS, "deinterlace" }, + { "bob", "Bob deinterlace mode.", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_DEINTERLACING_BOB }, .flags = FLAGS, "deinterlace" }, + { "advanced", "Advanced deinterlace mode. ", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_DEINTERLACING_ADVANCED }, .flags = FLAGS, "deinterlace" }, + + { "denoise", "denoise level [0, 100]", OFFSET(denoise), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, .flags = FLAGS }, + { "detail", "enhancement level [0, 100]", OFFSET(detail), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, .flags = FLAGS }, + { "framerate", "output framerate", OFFSET(framerate), AV_OPT_TYPE_RATIONAL, { .dbl = 0.0 },0, DBL_MAX, .flags = FLAGS }, + { "procamp", "Enable ProcAmp", OFFSET(procamp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = FLAGS}, + { "hue", "ProcAmp hue", OFFSET(hue), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, -180.0, 180.0, .flags = FLAGS}, + { "saturation", "ProcAmp saturation", OFFSET(saturation), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS}, + { "contrast", "ProcAmp contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS}, + { "brightness", "ProcAmp brightness", OFFSET(brightness), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, -100.0, 100.0, .flags = FLAGS}, + + { "cw", "set the width crop area expression", OFFSET(cw), AV_OPT_TYPE_STRING, { .str = "iw" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "ch", "set the height crop area expression", OFFSET(ch), AV_OPT_TYPE_STRING, { .str = "ih" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "cx", "set the x crop area expression", OFFSET(cx), AV_OPT_TYPE_STRING, { .str = "(in_w-out_w)/2" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "cy", "set the y crop area expression", OFFSET(cy), AV_OPT_TYPE_STRING, { .str = "(in_h-out_h)/2" }, CHAR_MIN, CHAR_MAX, FLAGS }, + + { "w", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS }, + { "width", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS }, + { "h", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS }, + { "height", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS }, + { NULL } +}; + +static const char *const var_names[] = { + "iw", "in_w", + "ih", "in_h", + "ow", "out_w", "w", + "oh", "out_h", "h", + "cw", + "ch", + "cx", + "cy", + NULL +}; + +enum var_name { + VAR_iW, VAR_IN_W, + VAR_iH, VAR_IN_H, + VAR_oW, VAR_OUT_W, VAR_W, + VAR_oH, VAR_OUT_H, VAR_H, + CW, + CH, + CX, + CY, + VAR_VARS_NB +}; + +static int eval_expr(AVFilterContext *ctx) +{ +#define PASS_EXPR(e, s) {\ + ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \ + if (ret < 0) {\ + av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\ + goto release;\ + }\ +} +#define CALC_EXPR(e, v, i) {\ + i = v = av_expr_eval(e, var_values, NULL); \ +} + VPPContext *vpp = ctx->priv; + double var_values[VAR_VARS_NB] = { NAN }; + AVExpr *w_expr = NULL, *h_expr = NULL; + AVExpr *cw_expr = NULL, *ch_expr = NULL; + AVExpr *cx_expr = NULL, *cy_expr = NULL; + int ret = 0; + + PASS_EXPR(cw_expr, vpp->cw); + PASS_EXPR(ch_expr, vpp->ch); + + PASS_EXPR(w_expr, vpp->ow); + PASS_EXPR(h_expr, vpp->oh); + + PASS_EXPR(cx_expr, vpp->cx); + PASS_EXPR(cy_expr, vpp->cy); + + var_values[VAR_iW] = + var_values[VAR_IN_W] = ctx->inputs[0]->w; + + var_values[VAR_iH] = + var_values[VAR_IN_H] = ctx->inputs[0]->h; + + /* crop params */ + CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w); + CALC_EXPR(ch_expr, var_values[CH], vpp->crop_h); + + /* calc again in case cw is relative to ch */ + CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w); + + CALC_EXPR(w_expr, + var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W], + vpp->out_width); + CALC_EXPR(h_expr, + var_values[VAR_OUT_H] = var_values[VAR_oH] = var_values[VAR_H], + vpp->out_height); + + /* calc again in case ow is relative to oh */ + CALC_EXPR(w_expr, + var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W], + vpp->out_width); + + + CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x); + CALC_EXPR(cy_expr, var_values[CY], vpp->crop_y); + + /* calc again in case cx is relative to cy */ + CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x); + + if ((vpp->crop_w != var_values[VAR_iW]) || (vpp->crop_h != var_values[VAR_iH])) + vpp->use_crop = 1; + +release: + av_expr_free(w_expr); + av_expr_free(h_expr); + av_expr_free(cw_expr); + av_expr_free(ch_expr); + av_expr_free(cx_expr); + av_expr_free(cy_expr); +#undef PASS_EXPR +#undef CALC_EXPR + + return ret; +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + VPPContext *vpp = ctx->priv; + int ret; + + if (vpp->framerate.den == 0 || vpp->framerate.num == 0) + vpp->framerate = inlink->frame_rate; + + if (av_cmp_q(vpp->framerate, inlink->frame_rate)) + vpp->use_frc = 1; + + ret = eval_expr(ctx); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "Fail to eval expr.\n"); + return ret; + } + + if (vpp->out_height == 0 || vpp->out_width == 0) { + vpp->out_width = inlink->w; + vpp->out_height = inlink->h; + } + + if (vpp->use_crop) { + vpp->crop_x = FFMAX(vpp->crop_x, 0); + vpp->crop_y = FFMAX(vpp->crop_y, 0); + + if(vpp->crop_w + vpp->crop_x > inlink->w) + vpp->crop_x = inlink->w - vpp->crop_w; + if(vpp->crop_h + vpp->crop_y > inlink->h) + vpp->crop_y = inlink->h - vpp->crop_h; + } + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + VPPContext *vpp = ctx->priv; + QSVVPPParam param = { NULL }; + QSVVPPCrop crop = { 0 }; + mfxExtBuffer *ext_buf[ENH_FILTERS_COUNT]; + + outlink->w = vpp->out_width; + outlink->h = vpp->out_height; + outlink->frame_rate = vpp->framerate; + outlink->time_base = av_inv_q(vpp->framerate); + + param.filter_frame = NULL; + param.out_sw_format = AV_PIX_FMT_NV12; + param.num_ext_buf = 0; + param.ext_buf = ext_buf; + + if (vpp->use_crop) { + crop.in_idx = 0; + crop.x = vpp->crop_x; + crop.y = vpp->crop_y; + crop.w = vpp->crop_w; + crop.h = vpp->crop_h; + + param.num_crop = 1; + param.crop = &crop; + } + + if (vpp->deinterlace) { + memset(&vpp->deinterlace_conf, 0, sizeof(mfxExtVPPDeinterlacing)); + vpp->deinterlace_conf.Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING; + vpp->deinterlace_conf.Header.BufferSz = sizeof(mfxExtVPPDeinterlacing); + vpp->deinterlace_conf.Mode = vpp->deinterlace == 1 ? + MFX_DEINTERLACING_BOB : MFX_DEINTERLACING_ADVANCED; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->deinterlace_conf; + } + + if (vpp->use_frc) { + memset(&vpp->frc_conf, 0, sizeof(mfxExtVPPFrameRateConversion)); + vpp->frc_conf.Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION; + vpp->frc_conf.Header.BufferSz = sizeof(mfxExtVPPFrameRateConversion); + vpp->frc_conf.Algorithm = MFX_FRCALGM_DISTRIBUTED_TIMESTAMP; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->frc_conf; + } + + if (vpp->denoise) { + memset(&vpp->denoise_conf, 0, sizeof(mfxExtVPPDenoise)); + vpp->denoise_conf.Header.BufferId = MFX_EXTBUFF_VPP_DENOISE; + vpp->denoise_conf.Header.BufferSz = sizeof(mfxExtVPPDenoise); + vpp->denoise_conf.DenoiseFactor = vpp->denoise; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->denoise_conf; + } + + if (vpp->detail) { + memset(&vpp->detail_conf, 0, sizeof(mfxExtVPPDetail)); + vpp->detail_conf.Header.BufferId = MFX_EXTBUFF_VPP_DETAIL; + vpp->detail_conf.Header.BufferSz = sizeof(mfxExtVPPDetail); + vpp->detail_conf.DetailFactor = vpp->detail; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->detail_conf; + } + + if (vpp->procamp) { + memset(&vpp->procamp_conf, 0, sizeof(mfxExtVPPProcAmp)); + vpp->procamp_conf.Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP; + vpp->procamp_conf.Header.BufferSz = sizeof(mfxExtVPPProcAmp); + vpp->procamp_conf.Hue = vpp->hue; + vpp->procamp_conf.Saturation = vpp->saturation; + vpp->procamp_conf.Contrast = vpp->contrast; + vpp->procamp_conf.Brightness = vpp->brightness; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->procamp_conf; + } + + return ff_qsvvpp_create(ctx, &vpp->qsv, ¶m); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *picref) +{ + VPPContext *vpp = inlink->dst->priv; + + return ff_qsvvpp_filter_frame(vpp->qsv, inlink, picref); +} + +static int query_formats(AVFilterContext *ctx) +{ + int ret; + AVFilterFormats *in_fmts, *out_fmts; + static const enum AVPixelFormat in_pix_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUYV422, + AV_PIX_FMT_RGB32, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat out_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + + in_fmts = ff_make_format_list(in_pix_fmts); + out_fmts = ff_make_format_list(out_pix_fmts); + ret = ff_formats_ref(in_fmts, &ctx->inputs[0]->out_formats); + if (ret < 0) + return ret; + ret = ff_formats_ref(out_fmts, &ctx->outputs[0]->in_formats); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold void vpp_uninit(AVFilterContext *ctx) +{ + VPPContext *vpp = ctx->priv; + + ff_qsvvpp_free(&vpp->qsv); +} + +static const AVClass vpp_class = { + .class_name = "vpp_qsv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVFilterPad vpp_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad vpp_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_vf_vpp_qsv = { + .name = "vpp_qsv", + .description = NULL_IF_CONFIG_SMALL("Quick Sync Video VPP."), + .priv_size = sizeof(VPPContext), + .query_formats = query_formats, + .uninit = vpp_uninit, + .inputs = vpp_inputs, + .outputs = vpp_outputs, + .priv_class = &vpp_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_waveform.c b/libavfilter/vf_waveform.c index 0c574742a..02a7046f3 100644 --- a/libavfilter/vf_waveform.c +++ b/libavfilter/vf_waveform.c @@ -295,6 +295,7 @@ static int query_formats(AVFilterContext *ctx) case FLAT: in_pix_fmts = in_flat_pix_fmts; break; case ACOLOR: case COLOR: in_pix_fmts = in_color_pix_fmts; break; + default: return AVERROR_BUG; } if (!ctx->inputs[0]->out_formats) { diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c index 694ac4499..f58d8ac2b 100644 --- a/libavfilter/vf_yadif.c +++ b/libavfilter/vf_yadif.c @@ -123,18 +123,20 @@ static void filter_edges(void *dst1, void *prev1, void *cur1, void *next1, uint8_t *prev2 = parity ? prev : cur ; uint8_t *next2 = parity ? cur : next; + const int edge = MAX_ALIGN - 1; + /* Only edge pixels need to be processed here. A constant value of false * for is_not_edge should let the compiler ignore the whole branch. */ FILTER(0, 3, 0) - dst = (uint8_t*)dst1 + w - (MAX_ALIGN-1); - prev = (uint8_t*)prev1 + w - (MAX_ALIGN-1); - cur = (uint8_t*)cur1 + w - (MAX_ALIGN-1); - next = (uint8_t*)next1 + w - (MAX_ALIGN-1); + dst = (uint8_t*)dst1 + w - edge; + prev = (uint8_t*)prev1 + w - edge; + cur = (uint8_t*)cur1 + w - edge; + next = (uint8_t*)next1 + w - edge; prev2 = (uint8_t*)(parity ? prev : cur); next2 = (uint8_t*)(parity ? cur : next); - FILTER(w - (MAX_ALIGN-1), w - 3, 1) + FILTER(w - edge, w - 3, 1) FILTER(w - 3, w, 0) } @@ -167,19 +169,22 @@ static void filter_edges_16bit(void *dst1, void *prev1, void *cur1, void *next1, int x; uint16_t *prev2 = parity ? prev : cur ; uint16_t *next2 = parity ? cur : next; + + const int edge = MAX_ALIGN / 2 - 1; + mrefs /= 2; prefs /= 2; FILTER(0, 3, 0) - dst = (uint16_t*)dst1 + w - (MAX_ALIGN/2-1); - prev = (uint16_t*)prev1 + w - (MAX_ALIGN/2-1); - cur = (uint16_t*)cur1 + w - (MAX_ALIGN/2-1); - next = (uint16_t*)next1 + w - (MAX_ALIGN/2-1); + dst = (uint16_t*)dst1 + w - edge; + prev = (uint16_t*)prev1 + w - edge; + cur = (uint16_t*)cur1 + w - edge; + next = (uint16_t*)next1 + w - edge; prev2 = (uint16_t*)(parity ? prev : cur); next2 = (uint16_t*)(parity ? cur : next); - FILTER(w - (MAX_ALIGN/2-1), w - 3, 1) + FILTER(w - edge, w - 3, 1) FILTER(w - 3, w, 0) } @@ -193,6 +198,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) int slice_start = (td->h * jobnr ) / nb_jobs; int slice_end = (td->h * (jobnr+1)) / nb_jobs; int y; + int edge = 3 + MAX_ALIGN / df - 1; /* filtering reads 3 pixels to the left/right; to avoid invalid reads, * we need to call the c variant which avoids this for border pixels @@ -205,7 +211,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) uint8_t *dst = &td->frame->data[td->plane][y * td->frame->linesize[td->plane]]; int mode = y == 1 || y + 2 == td->h ? 2 : s->mode; s->filter_line(dst + pix_3, prev + pix_3, cur + pix_3, - next + pix_3, td->w - (3 + MAX_ALIGN/df-1), + next + pix_3, td->w - edge, y + 1 < td->h ? refs : -refs, y ? -refs : refs, td->parity ^ td->tff, mode); diff --git a/libavfilter/vf_zscale.c b/libavfilter/vf_zscale.c index c303dd4d6..6e1d36cb4 100644 --- a/libavfilter/vf_zscale.c +++ b/libavfilter/vf_zscale.c @@ -321,7 +321,7 @@ static int print_zimg_error(AVFilterContext *ctx) av_log(ctx, AV_LOG_ERROR, "code %d: %s\n", err_code, err_msg); - return err_code; + return AVERROR_EXTERNAL; } static int convert_chroma_location(enum AVChromaLocation chroma_location) @@ -353,16 +353,26 @@ static int convert_matrix(enum AVColorSpace colorspace) return ZIMG_MATRIX_709; case AVCOL_SPC_UNSPECIFIED: return ZIMG_MATRIX_UNSPECIFIED; + case AVCOL_SPC_FCC: + return ZIMG_MATRIX_FCC; case AVCOL_SPC_BT470BG: return ZIMG_MATRIX_470BG; case AVCOL_SPC_SMPTE170M: return ZIMG_MATRIX_170M; + case AVCOL_SPC_SMPTE240M: + return ZIMG_MATRIX_240M; case AVCOL_SPC_YCGCO: return ZIMG_MATRIX_YCGCO; case AVCOL_SPC_BT2020_NCL: return ZIMG_MATRIX_2020_NCL; case AVCOL_SPC_BT2020_CL: return ZIMG_MATRIX_2020_CL; + case AVCOL_SPC_CHROMA_DERIVED_NCL: + return ZIMG_MATRIX_CHROMATICITY_DERIVED_NCL; + case AVCOL_SPC_CHROMA_DERIVED_CL: + return ZIMG_MATRIX_CHROMATICITY_DERIVED_CL; + case AVCOL_SPC_ICTCP: + return ZIMG_MATRIX_ICTCP; } return ZIMG_MATRIX_UNSPECIFIED; } @@ -374,10 +384,22 @@ static int convert_trc(enum AVColorTransferCharacteristic color_trc) return ZIMG_TRANSFER_UNSPECIFIED; case AVCOL_TRC_BT709: return ZIMG_TRANSFER_709; + case AVCOL_TRC_GAMMA22: + return ZIMG_TRANSFER_470_M; + case AVCOL_TRC_GAMMA28: + return ZIMG_TRANSFER_470_BG; case AVCOL_TRC_SMPTE170M: return ZIMG_TRANSFER_601; + case AVCOL_TRC_SMPTE240M: + return ZIMG_TRANSFER_240M; case AVCOL_TRC_LINEAR: return ZIMG_TRANSFER_LINEAR; + case AVCOL_TRC_LOG: + return ZIMG_TRANSFER_LOG_100; + case AVCOL_TRC_LOG_SQRT: + return ZIMG_TRANSFER_LOG_316; + case AVCOL_TRC_IEC61966_2_4: + return ZIMG_TRANSFER_IEC_61966_2_4; case AVCOL_TRC_BT2020_10: return ZIMG_TRANSFER_2020_10; case AVCOL_TRC_BT2020_12: @@ -399,14 +421,26 @@ static int convert_primaries(enum AVColorPrimaries color_primaries) return ZIMG_PRIMARIES_UNSPECIFIED; case AVCOL_PRI_BT709: return ZIMG_PRIMARIES_709; + case AVCOL_PRI_BT470M: + return ZIMG_PRIMARIES_470_M; + case AVCOL_PRI_BT470BG: + return ZIMG_PRIMARIES_470_BG; case AVCOL_PRI_SMPTE170M: return ZIMG_PRIMARIES_170M; case AVCOL_PRI_SMPTE240M: return ZIMG_PRIMARIES_240M; + case AVCOL_PRI_FILM: + return ZIMG_PRIMARIES_FILM; case AVCOL_PRI_BT2020: return ZIMG_PRIMARIES_2020; + case AVCOL_PRI_SMPTE428: + return ZIMG_PRIMARIES_ST428; + case AVCOL_PRI_SMPTE431: + return ZIMG_PRIMARIES_ST431_2; case AVCOL_PRI_SMPTE432: return ZIMG_PRIMARIES_ST432_1; + case AVCOL_PRI_JEDEC_P22: + return ZIMG_PRIMARIES_EBU3213_E; } return ZIMG_PRIMARIES_UNSPECIFIED; } @@ -581,7 +615,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) s->alpha_dst_format.width = out->width; s->alpha_dst_format.height = out->height; s->alpha_dst_format.depth = odesc->comp[0].depth; - s->alpha_dst_format.pixel_type = (desc->flags & AV_PIX_FMT_FLAG_FLOAT) ? ZIMG_PIXEL_FLOAT : odesc->comp[0].depth > 8 ? ZIMG_PIXEL_WORD : ZIMG_PIXEL_BYTE; + s->alpha_dst_format.pixel_type = (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) ? ZIMG_PIXEL_FLOAT : odesc->comp[0].depth > 8 ? ZIMG_PIXEL_WORD : ZIMG_PIXEL_BYTE; s->alpha_dst_format.color_family = ZIMG_COLOR_GREY; zimg_filter_graph_free(s->alpha_graph); @@ -624,7 +658,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) ret = zimg_filter_graph_process(s->graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); if (ret) { - print_zimg_error(link->dst); + ret = print_zimg_error(link->dst); goto fail; } @@ -639,7 +673,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) ret = zimg_filter_graph_process(s->alpha_graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); if (ret) { - print_zimg_error(link->dst); + ret = print_zimg_error(link->dst); goto fail; } } else if (odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { @@ -673,6 +707,7 @@ static void uninit(AVFilterContext *ctx) ZScaleContext *s = ctx->priv; zimg_filter_graph_free(s->graph); + zimg_filter_graph_free(s->alpha_graph); av_freep(&s->tmp); s->tmp_size = 0; } @@ -734,8 +769,8 @@ static const AVOption zscale_options[] = { { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "range" }, { "tv", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_RANGE_LIMITED}, 0, 0, FLAGS, "range" }, { "pc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_RANGE_FULL}, 0, 0, FLAGS, "range" }, - { "primaries", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, - { "p", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, + { "primaries", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "p", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "primaries" }, { "709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_709}, 0, 0, FLAGS, "primaries" }, { "unspecified", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_UNSPECIFIED}, 0, 0, FLAGS, "primaries" }, @@ -744,12 +779,18 @@ static const AVOption zscale_options[] = { { "2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_2020}, 0, 0, FLAGS, "primaries" }, { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_UNSPECIFIED}, 0, 0, FLAGS, "primaries" }, { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_709}, 0, 0, FLAGS, "primaries" }, + { "bt470m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_470_M}, 0, 0, FLAGS, "primaries" }, + { "bt470bg", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_470_BG}, 0, 0, FLAGS, "primaries" }, { "smpte170m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_170M}, 0, 0, FLAGS, "primaries" }, { "smpte240m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_240M}, 0, 0, FLAGS, "primaries" }, + { "film", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_FILM}, 0, 0, FLAGS, "primaries" }, { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_2020}, 0, 0, FLAGS, "primaries" }, + { "smpte428", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_ST428}, 0, 0, FLAGS, "primaries" }, + { "smpte431", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_ST431_2}, 0, 0, FLAGS, "primaries" }, { "smpte432", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_ST432_1}, 0, 0, FLAGS, "primaries" }, - { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, - { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, + { "jedec-p22", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_EBU3213_E}, 0, 0, FLAGS, "primaries" }, + { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, + { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "transfer" }, { "709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_709}, 0, 0, FLAGS, "transfer" }, { "unspecified", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_UNSPECIFIED}, 0, 0, FLAGS, "transfer" }, @@ -758,16 +799,21 @@ static const AVOption zscale_options[] = { { "2020_10", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_10}, 0, 0, FLAGS, "transfer" }, { "2020_12", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_12}, 0, 0, FLAGS, "transfer" }, { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_UNSPECIFIED}, 0, 0, FLAGS, "transfer" }, + { "bt470m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_470_M}, 0, 0, FLAGS, "transfer" }, + { "bt470bg", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_470_BG}, 0, 0, FLAGS, "transfer" }, { "smpte170m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_601}, 0, 0, FLAGS, "transfer" }, { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_709}, 0, 0, FLAGS, "transfer" }, { "linear", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_LINEAR}, 0, 0, FLAGS, "transfer" }, + { "log100", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_LOG_100}, 0, 0, FLAGS, "transfer" }, + { "log316", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_LOG_316}, 0, 0, FLAGS, "transfer" }, { "bt2020-10", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_10}, 0, 0, FLAGS, "transfer" }, { "bt2020-12", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_12}, 0, 0, FLAGS, "transfer" }, { "smpte2084", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_ST2084}, 0, 0, FLAGS, "transfer" }, + { "iec61966-2-4", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_IEC_61966_2_4},0, 0, FLAGS, "transfer" }, { "iec61966-2-1", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_IEC_61966_2_1},0, 0, FLAGS, "transfer" }, { "arib-std-b67", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_ARIB_B67}, 0, 0, FLAGS, "transfer" }, - { "matrix", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, - { "m", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, + { "matrix", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, + { "m", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "matrix" }, { "709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_709}, 0, 0, FLAGS, "matrix" }, { "unspecified", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_UNSPECIFIED}, 0, 0, FLAGS, "matrix" }, @@ -776,21 +822,27 @@ static const AVOption zscale_options[] = { { "2020_ncl", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_NCL}, 0, 0, FLAGS, "matrix" }, { "2020_cl", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_CL}, 0, 0, FLAGS, "matrix" }, { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_UNSPECIFIED}, 0, 0, FLAGS, "matrix" }, + { "gbr", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_RGB}, 0, 0, FLAGS, "matrix" }, { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_709}, 0, 0, FLAGS, "matrix" }, + { "fcc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_FCC}, 0, 0, FLAGS, "matrix" }, { "bt470bg", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_470BG}, 0, 0, FLAGS, "matrix" }, { "smpte170m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_170M}, 0, 0, FLAGS, "matrix" }, + { "smpte2400m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_240M}, 0, 0, FLAGS, "matrix" }, { "ycgco", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_YCGCO}, 0, 0, FLAGS, "matrix" }, { "bt2020nc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_NCL}, 0, 0, FLAGS, "matrix" }, { "bt2020c", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_CL}, 0, 0, FLAGS, "matrix" }, + { "chroma-derived-nc",0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_CHROMATICITY_DERIVED_NCL}, 0, 0, FLAGS, "matrix" }, + { "chroma-derived-c", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_CHROMATICITY_DERIVED_CL}, 0, 0, FLAGS, "matrix" }, + { "ictcp", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_ICTCP}, 0, 0, FLAGS, "matrix" }, { "in_range", "set input color range", OFFSET(range_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_RANGE_FULL, FLAGS, "range" }, { "rangein", "set input color range", OFFSET(range_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_RANGE_FULL, FLAGS, "range" }, { "rin", "set input color range", OFFSET(range_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_RANGE_FULL, FLAGS, "range" }, - { "primariesin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, - { "pin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, - { "transferin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, - { "tin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, - { "matrixin", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, - { "min", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, + { "primariesin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "pin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "transferin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, + { "tin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, + { "matrixin", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, + { "min", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, { "chromal", "set output chroma location", OFFSET(chromal), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_CHROMA_BOTTOM, FLAGS, "chroma" }, { "c", "set output chroma location", OFFSET(chromal), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_CHROMA_BOTTOM, FLAGS, "chroma" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "chroma" }, diff --git a/libavfilter/video.c b/libavfilter/video.c index 6f9020b9f..7a8e58779 100644 --- a/libavfilter/video.c +++ b/libavfilter/video.c @@ -43,6 +43,7 @@ AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h) AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h) { + AVFrame *frame = NULL; int pool_width = 0; int pool_height = 0; int pool_align = 0; @@ -86,7 +87,13 @@ AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h) } } - return ff_frame_pool_get(link->frame_pool); + frame = ff_frame_pool_get(link->frame_pool); + if (!frame) + return NULL; + + frame->sample_aspect_ratio = link->sample_aspect_ratio; + + return frame; } AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h) diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c index fe0d50aa4..a790974d1 100644 --- a/libavfilter/vsrc_testsrc.c +++ b/libavfilter/vsrc_testsrc.c @@ -857,8 +857,8 @@ static void test2_fill_picture(AVFilterContext *ctx, AVFrame *frame) uint8_t alpha[256]; r = s->pts; - for (y = ymin; y < ymax - 15; y += 16) { - for (x = xmin; x < xmax - 15; x += 16) { + for (y = ymin; y + 15 < ymax; y += 16) { + for (x = xmin; x + 15 < xmax; x += 16) { if ((x ^ y) & 16) continue; for (i = 0; i < 256; i++) { diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index 343162588..2fc5c6264 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -5,6 +5,7 @@ OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp_init.o OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_init.o +OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip_init.o OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet_init.o OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace_init.o @@ -20,6 +21,7 @@ OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o OBJS-$(CONFIG_SSIM_FILTER) += x86/vf_ssim_init.o OBJS-$(CONFIG_STEREO3D_FILTER) += x86/vf_stereo3d_init.o OBJS-$(CONFIG_TBLEND_FILTER) += x86/vf_blend_init.o +OBJS-$(CONFIG_THRESHOLD_FILTER) += x86/vf_threshold_init.o OBJS-$(CONFIG_TINTERLACE_FILTER) += x86/vf_tinterlace_init.o OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o OBJS-$(CONFIG_W3FDIF_FILTER) += x86/vf_w3fdif_init.o @@ -31,6 +33,7 @@ X86ASM-OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif.o X86ASM-OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp.o X86ASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o X86ASM-OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun.o +X86ASM-OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip.o X86ASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.o X86ASM-OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet.o X86ASM-OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace.o @@ -46,6 +49,7 @@ X86ASM-OBJS-$(CONFIG_SHOWCQT_FILTER) += x86/avf_showcqt.o X86ASM-OBJS-$(CONFIG_SSIM_FILTER) += x86/vf_ssim.o X86ASM-OBJS-$(CONFIG_STEREO3D_FILTER) += x86/vf_stereo3d.o X86ASM-OBJS-$(CONFIG_TBLEND_FILTER) += x86/vf_blend.o +X86ASM-OBJS-$(CONFIG_THRESHOLD_FILTER) += x86/vf_threshold.o X86ASM-OBJS-$(CONFIG_TINTERLACE_FILTER) += x86/vf_interlace.o X86ASM-OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume.o X86ASM-OBJS-$(CONFIG_W3FDIF_FILTER) += x86/vf_w3fdif.o diff --git a/libavfilter/x86/vf_hflip.asm b/libavfilter/x86/vf_hflip.asm new file mode 100644 index 000000000..285618954 --- /dev/null +++ b/libavfilter/x86/vf_hflip.asm @@ -0,0 +1,90 @@ +;***************************************************************************** +;* x86-optimized functions for hflip filter +;* +;* 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 "libavutil/x86/x86util.asm" + +SECTION_RODATA + +pb_flip_byte: db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +pb_flip_short: db 14,15,12,13,10,11,8,9,6,7,4,5,2,3,0,1 + +SECTION .text + +;%1 byte or short, %2 b or w, %3 size in byte (1 for byte, 2 for short) +%macro HFLIP 3 +cglobal hflip_%1, 3, 5, 3, src, dst, w, r, x + VBROADCASTI128 m0, [pb_flip_%1] + xor xq, xq +%if %3 == 1 + movsxdifnidn wq, wd +%else ; short + add wd, wd +%endif + mov rq, wq + and rq, 2 * mmsize - 1 + cmp wq, 2 * mmsize + jl .loop1 + sub wq, rq + + .loop0: + neg xq +%if mmsize == 32 + vpermq m1, [srcq + xq - mmsize + %3], 0x4e; flip each lane at load + vpermq m2, [srcq + xq - 2 * mmsize + %3], 0x4e; flip each lane at load +%else + movu m1, [srcq + xq - mmsize + %3] + movu m2, [srcq + xq - 2 * mmsize + %3] +%endif + pshufb m1, m0 + pshufb m2, m0 + neg xq + movu [dstq + xq ], m1 + movu [dstq + xq + mmsize], m2 + add xq, mmsize * 2 + cmp xq, wq + jl .loop0 + + cmp rq, 0 + je .end + add wq, rq + + .loop1: + neg xq + mov r%2, [srcq + xq] + neg xq + mov [dstq + xq], r%2 + add xq, %3 + cmp xq, wq + jl .loop1 + .end: + RET +%endmacro + +INIT_XMM ssse3 +HFLIP byte, b, 1 +HFLIP short, w, 2 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +HFLIP byte, b, 1 +HFLIP short, w, 2 +%endif diff --git a/libavfilter/x86/vf_hflip_init.c b/libavfilter/x86/vf_hflip_init.c new file mode 100644 index 000000000..0ac399b0d --- /dev/null +++ b/libavfilter/x86/vf_hflip_init.c @@ -0,0 +1,53 @@ +/* + * 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 "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/hflip.h" + +void ff_hflip_byte_ssse3(const uint8_t *src, uint8_t *dst, int w); +void ff_hflip_byte_avx2(const uint8_t *src, uint8_t *dst, int w); +void ff_hflip_short_ssse3(const uint8_t *src, uint8_t *dst, int w); +void ff_hflip_short_avx2(const uint8_t *src, uint8_t *dst, int w); + +av_cold void ff_hflip_init_x86(FlipContext *s, int step[4], int nb_planes) +{ + int cpu_flags = av_get_cpu_flags(); + int i; + + for (i = 0; i < nb_planes; i++) { + if (step[i] == 1) { + if (EXTERNAL_SSSE3(cpu_flags)) { + s->flip_line[i] = ff_hflip_byte_ssse3; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->flip_line[i] = ff_hflip_byte_avx2; + } + } else if (step[i] == 2) { + if (EXTERNAL_SSSE3(cpu_flags)) { + s->flip_line[i] = ff_hflip_short_ssse3; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->flip_line[i] = ff_hflip_short_avx2; + } + } + } +} diff --git a/libavfilter/x86/vf_interlace.asm b/libavfilter/x86/vf_interlace.asm index 7c0065d4d..a6c65b805 100644 --- a/libavfilter/x86/vf_interlace.asm +++ b/libavfilter/x86/vf_interlace.asm @@ -39,9 +39,23 @@ SECTION .text pcmpeq%1 m6, m6 + test hq, mmsize + je .loop + + ;process 1 * mmsize + movu m0, [mrefq+hq] + pavg%1 m0, [prefq+hq] + pxor m0, m6 + pxor m2, m6, [srcq+hq] + pavg%1 m0, m2 + pxor m0, m6 + mova [dstq+hq], m0 + add hq, mmsize + jge .end + .loop: - mova m0, [mrefq+hq] - mova m1, [mrefq+hq+mmsize] + movu m0, [mrefq+hq] + movu m1, [mrefq+hq+mmsize] pavg%1 m0, [prefq+hq] pavg%1 m1, [prefq+hq+mmsize] pxor m0, m6 @@ -57,7 +71,9 @@ SECTION .text add hq, 2*mmsize jl .loop -REP_RET + +.end: + REP_RET %endmacro %macro LOWPASS_LINE 0 @@ -73,8 +89,8 @@ cglobal lowpass_line_16, 5, 5, 7, dst, h, src, mref, pref cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref pxor m7, m7 .loop: - mova m0, [srcq+mrefq] - mova m2, [srcq+prefq] + movu m0, [srcq+mrefq] + movu m2, [srcq+prefq] mova m1, m0 mova m3, m2 punpcklbw m0, m7 @@ -85,7 +101,7 @@ cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref paddw m1, m3 mova m6, m0 mova m5, m1 - mova m2, [srcq] + movu m2, [srcq] mova m3, m2 punpcklbw m2, m7 punpckhbw m3, m7 @@ -100,8 +116,8 @@ cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref pcmpgtw m6, m2 pcmpgtw m5, m3 packsswb m6, m5 - mova m2, [srcq+mrefq*2] - mova m4, [srcq+prefq*2] + movu m2, [srcq+mrefq*2] + movu m4, [srcq+prefq*2] mova m3, m2 mova m5, m4 punpcklbw m2, m7 @@ -118,8 +134,9 @@ cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref psrlw m1, 3 packuswb m0, m1 mova m1, m0 - pmaxub m0, [srcq] - pminub m1, [srcq] + movu m2, [srcq] + pmaxub m0, m2 + pminub m1, m2 pand m0, m6 pandn m6, m1 por m0, m6 @@ -134,18 +151,18 @@ REP_RET cglobal lowpass_line_complex_12, 5, 5, 8, 16, dst, h, src, mref, pref, clip_max movd m7, DWORD clip_maxm SPLATW m7, m7, 0 - mova [rsp], m7 + movu [rsp], m7 .loop: - mova m0, [srcq+mrefq] - mova m1, [srcq+mrefq+mmsize] - mova m2, [srcq+prefq] - mova m3, [srcq+prefq+mmsize] + movu m0, [srcq+mrefq] + movu m1, [srcq+mrefq+mmsize] + movu m2, [srcq+prefq] + movu m3, [srcq+prefq+mmsize] paddw m0, m2 paddw m1, m3 mova m6, m0 mova m7, m1 - mova m2, [srcq] - mova m3, [srcq+mmsize] + movu m2, [srcq] + movu m3, [srcq+mmsize] paddw m0, m2 paddw m1, m3 psllw m2, 1 @@ -156,10 +173,10 @@ cglobal lowpass_line_complex_12, 5, 5, 8, 16, dst, h, src, mref, pref, clip_max psllw m1, 1 pcmpgtw m6, m2 pcmpgtw m7, m3 - mova m2, [srcq+2*mrefq] - mova m3, [srcq+2*mrefq+mmsize] - mova m4, [srcq+2*prefq] - mova m5, [srcq+2*prefq+mmsize] + movu m2, [srcq+2*mrefq] + movu m3, [srcq+2*mrefq+mmsize] + movu m4, [srcq+2*prefq] + movu m5, [srcq+2*prefq+mmsize] paddw m2, m4 paddw m3, m5 paddw m0, [pw_4] @@ -172,10 +189,12 @@ cglobal lowpass_line_complex_12, 5, 5, 8, 16, dst, h, src, mref, pref, clip_max pminsw m1, [rsp] mova m2, m0 mova m3, m1 - pmaxsw m0, [srcq] - pmaxsw m1, [srcq+mmsize] - pminsw m2, [srcq] - pminsw m3, [srcq+mmsize] + movu m4, [srcq] + pmaxsw m0, m4 + pminsw m2, m4 + movu m4, [srcq + mmsize] + pmaxsw m1, m4 + pminsw m3, m4 pand m0, m6 pand m1, m7 pandn m6, m2 @@ -198,5 +217,10 @@ LOWPASS_LINE INIT_XMM avx LOWPASS_LINE +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +LOWPASS_LINE +%endif + INIT_XMM sse2 LOWPASS_LINE_COMPLEX diff --git a/libavfilter/x86/vf_interlace_init.c b/libavfilter/x86/vf_interlace_init.c index 70fe86ccf..0de0fea38 100644 --- a/libavfilter/x86/vf_interlace_init.c +++ b/libavfilter/x86/vf_interlace_init.c @@ -32,6 +32,9 @@ void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -39,6 +42,9 @@ void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_16_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_16_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -48,11 +54,11 @@ void ff_lowpass_line_complex_12_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); -av_cold void ff_interlace_init_x86(InterlaceContext *s) +av_cold void ff_interlace_init_x86(InterlaceContext *s, int depth) { int cpu_flags = av_get_cpu_flags(); - if (s->csp->comp[0].depth > 8) { + if (depth > 8) { if (EXTERNAL_SSE2(cpu_flags)) { if (s->lowpass == VLPF_LIN) s->lowpass_line = ff_lowpass_line_16_sse2; @@ -62,6 +68,9 @@ av_cold void ff_interlace_init_x86(InterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (s->lowpass == VLPF_LIN) s->lowpass_line = ff_lowpass_line_16_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) + if (s->lowpass == VLPF_LIN) + s->lowpass_line = ff_lowpass_line_16_avx2; } else { if (EXTERNAL_SSE2(cpu_flags)) { if (s->lowpass == VLPF_LIN) @@ -72,5 +81,8 @@ av_cold void ff_interlace_init_x86(InterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (s->lowpass == VLPF_LIN) s->lowpass_line = ff_lowpass_line_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) + if (s->lowpass == VLPF_LIN) + s->lowpass_line = ff_lowpass_line_avx2; } } diff --git a/libavfilter/x86/vf_threshold.asm b/libavfilter/x86/vf_threshold.asm new file mode 100644 index 000000000..098069b08 --- /dev/null +++ b/libavfilter/x86/vf_threshold.asm @@ -0,0 +1,92 @@ +;***************************************************************************** +;* x86-optimized functions for threshold filter +;* +;* 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 "libavutil/x86/x86util.asm" + +SECTION_RODATA + +pb_128: times 16 db 128 +pb_128_0 : times 8 db 0, 128 + +SECTION .text + +;%1 depth (8 or 16) ; %2 b or w ; %3 constant +%macro THRESHOLD 3 +%if ARCH_X86_64 +cglobal threshold%1, 10, 13, 5, in, threshold, min, max, out, ilinesize, tlinesize, flinesize, slinesize, olinesize, w, h, x + mov wd, dword wm + mov hd, dword hm +%else +cglobal threshold%1, 5, 7, 5, in, threshold, min, max, out, w, x + mov wd, r10m +%define ilinesizeq r5mp +%define tlinesizeq r6mp +%define flinesizeq r7mp +%define slinesizeq r8mp +%define olinesizeq r9mp +%define hd r11mp +%endif + VBROADCASTI128 m4, [%3] +%if %1 == 16 + add wq, wq ; w *= 2 (16 bits instead of 8) +%endif + add inq, wq + add thresholdq, wq + add minq, wq + add maxq, wq + add outq, wq + neg wq +.nextrow: + mov xq, wq + + .loop: + movu m1, [inq + xq] + movu m0, [thresholdq + xq] + movu m2, [minq + xq] + movu m3, [maxq + xq] + pxor m0, m4 + pxor m1, m4 + pcmpgt%2 m0, m1 + PBLENDVB m3, m2, m0 + movu [outq + xq], m3 + add xq, mmsize + jl .loop + + add inq, ilinesizeq + add thresholdq, tlinesizeq + add minq, flinesizeq + add maxq, slinesizeq + add outq, olinesizeq + sub hd, 1 + jg .nextrow +RET +%endmacro + +INIT_XMM sse4 +THRESHOLD 8, b, pb_128 +THRESHOLD 16, w, pb_128_0 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +THRESHOLD 8, b, pb_128 +THRESHOLD 16, w, pb_128_0 +%endif diff --git a/libavfilter/x86/vf_threshold_init.c b/libavfilter/x86/vf_threshold_init.c new file mode 100644 index 000000000..8e4229679 --- /dev/null +++ b/libavfilter/x86/vf_threshold_init.c @@ -0,0 +1,59 @@ +/* + * 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 "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/threshold.h" + +#define THRESHOLD_FUNC(depth, opt) \ +void ff_threshold##depth##_##opt(const uint8_t *in, const uint8_t *threshold,\ + const uint8_t *min, const uint8_t *max, \ + uint8_t *out, \ + ptrdiff_t ilinesize, ptrdiff_t tlinesize, \ + ptrdiff_t flinesize, ptrdiff_t slinesize, \ + ptrdiff_t olinesize, \ + int w, int h); + +THRESHOLD_FUNC(8, sse4) +THRESHOLD_FUNC(8, avx2) +THRESHOLD_FUNC(16, sse4) +THRESHOLD_FUNC(16, avx2) + +av_cold void ff_threshold_init_x86(ThresholdContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (s->depth == 8) { + if (EXTERNAL_SSE4(cpu_flags)) { + s->threshold = ff_threshold8_sse4; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->threshold = ff_threshold8_avx2; + } + } else if (s->depth == 16) { + if (EXTERNAL_SSE4(cpu_flags)) { + s->threshold = ff_threshold16_sse4; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->threshold = ff_threshold16_avx2; + } + } +} diff --git a/libavfilter/x86/vf_tinterlace_init.c b/libavfilter/x86/vf_tinterlace_init.c index 209812964..2c9b1de58 100644 --- a/libavfilter/x86/vf_tinterlace_init.c +++ b/libavfilter/x86/vf_tinterlace_init.c @@ -33,6 +33,9 @@ void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -40,6 +43,9 @@ void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_16_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_16_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -63,6 +69,11 @@ av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (!(s->flags & TINTERLACE_FLAG_CVLPF)) s->lowpass_line = ff_lowpass_line_16_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + if (!(s->flags & TINTERLACE_FLAG_CVLPF)) { + s->lowpass_line = ff_lowpass_line_16_avx2; + } + } } else { if (EXTERNAL_SSE2(cpu_flags)) { if (!(s->flags & TINTERLACE_FLAG_CVLPF)) @@ -73,5 +84,10 @@ av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (!(s->flags & TINTERLACE_FLAG_CVLPF)) s->lowpass_line = ff_lowpass_line_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + if (!(s->flags & TINTERLACE_FLAG_CVLPF)) { + s->lowpass_line = ff_lowpass_line_avx2; + } + } } } diff --git a/libavfilter/x86/yadif-16.asm b/libavfilter/x86/yadif-16.asm index 79d127dfa..9053b378a 100644 --- a/libavfilter/x86/yadif-16.asm +++ b/libavfilter/x86/yadif-16.asm @@ -54,30 +54,6 @@ SECTION .text %endif %endmacro -%macro PMINSD 3 -%if cpuflag(sse4) - pminsd %1, %2 -%else - mova %3, %2 - pcmpgtd %3, %1 - pand %1, %3 - pandn %3, %2 - por %1, %3 -%endif -%endmacro - -%macro PMAXSD 3 -%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 PMAXUW 2 %if cpuflag(sse4) pmaxuw %1, %2 diff --git a/libavformat/.gitignore b/libavformat/.gitignore new file mode 100644 index 000000000..cdc24b717 --- /dev/null +++ b/libavformat/.gitignore @@ -0,0 +1 @@ +/protocol_list.c diff --git a/libavformat/Makefile b/libavformat/Makefile index df709c29d..de0de921c 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -87,11 +87,15 @@ OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o id3v2enc.o OBJS-$(CONFIG_AIX_DEMUXER) += aixdec.o OBJS-$(CONFIG_AMR_DEMUXER) += amr.o OBJS-$(CONFIG_AMR_MUXER) += amr.o +OBJS-$(CONFIG_AMRNB_DEMUXER) += amr.o +OBJS-$(CONFIG_AMRWB_DEMUXER) += amr.o OBJS-$(CONFIG_ANM_DEMUXER) += anm.o OBJS-$(CONFIG_APC_DEMUXER) += apc.o OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o OBJS-$(CONFIG_APNG_DEMUXER) += apngdec.o OBJS-$(CONFIG_APNG_MUXER) += apngenc.o +OBJS-$(CONFIG_APTX_DEMUXER) += aptxdec.o rawdec.o +OBJS-$(CONFIG_APTX_MUXER) += rawenc.o OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o OBJS-$(CONFIG_ASF_DEMUXER) += asfdec_f.o asf.o asfcrypt.o \ avlanguage.o @@ -120,8 +124,7 @@ OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o OBJS-$(CONFIG_BFSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o voc_packet.o vocdec.o voc.o -OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ - replaygain.o +OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov_chan.o mov_esds.o OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o @@ -132,8 +135,8 @@ OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o OBJS-$(CONFIG_CRC_MUXER) += crcenc.o OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o OBJS-$(CONFIG_DATA_MUXER) += rawenc.o -OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o -OBJS-$(CONFIG_DASH_DEMUXER) += dashdec.o +OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o hlsplaylist.o +OBJS-$(CONFIG_DASH_DEMUXER) += dash.o dashdec.o OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o @@ -158,8 +161,6 @@ OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o OBJS-$(CONFIG_EAC3_MUXER) += rawenc.o OBJS-$(CONFIG_EPAF_DEMUXER) += epafdec.o pcm.o -OBJS-$(CONFIG_FFM_DEMUXER) += ffmdec.o -OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o OBJS-$(CONFIG_FFMETADATA_DEMUXER) += ffmetadec.o OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o OBJS-$(CONFIG_FIFO_MUXER) += fifo.o @@ -212,7 +213,7 @@ OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o -OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o +OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_ICO_MUXER) += icoenc.o @@ -292,7 +293,7 @@ OBJS-$(CONFIG_MLV_DEMUXER) += mlvdec.o riffdec.o OBJS-$(CONFIG_MM_DEMUXER) += mm.o OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o -OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o replaygain.o +OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o mov_esds.o replaygain.o OBJS-$(CONFIG_MOV_MUXER) += movenc.o avc.o hevc.o vpcc.o \ movenchint.o mov_chan.o rtp.o \ movenccenc.o rawutils.o @@ -328,6 +329,7 @@ OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o +OBJS-$(CONFIG_NSP_DEMUXER) += nspdec.o OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o OBJS-$(CONFIG_NULL_MUXER) += nullenc.o OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o isom.o @@ -491,6 +493,7 @@ OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o OBJS-$(CONFIG_TTA_MUXER) += ttaenc.o apetag.o img2.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o +OBJS-$(CONFIG_TY_DEMUXER) += ty.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o OBJS-$(CONFIG_V210_DEMUXER) += v210.o @@ -560,7 +563,7 @@ OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o -OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o +OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o @@ -575,22 +578,24 @@ OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf.o OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o -OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o +OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o OBJS-$(CONFIG_TEE_PROTOCOL) += teeproto.o tee_common.o OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o -OBJS-$(CONFIG_TLS_GNUTLS_PROTOCOL) += tls_gnutls.o tls.o -OBJS-$(CONFIG_TLS_OPENSSL_PROTOCOL) += tls_openssl.o tls.o -OBJS-$(CONFIG_TLS_SCHANNEL_PROTOCOL) += tls_schannel.o tls.o -OBJS-$(CONFIG_TLS_SECURETRANSPORT_PROTOCOL) += tls_securetransport.o tls.o +TLS-OBJS-$(CONFIG_GNUTLS) += tls_gnutls.o +TLS-OBJS-$(CONFIG_LIBTLS) += tls_libtls.o +TLS-OBJS-$(CONFIG_OPENSSL) += tls_openssl.o +TLS-OBJS-$(CONFIG_SECURETRANSPORT) += tls_securetransport.o +TLS-OBJS-$(CONFIG_SCHANNEL) += tls_schannel.o +OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o $(TLS-OBJS-yes) OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index 364b33404..36d558ff5 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -139,7 +139,11 @@ static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_INVALIDDATA; } - return av_append_packet(s->pb, pkt, fsize - ADTS_HEADER_SIZE); + ret = av_append_packet(s->pb, pkt, fsize - ADTS_HEADER_SIZE); + if (ret < 0) + av_packet_unref(pkt); + + return ret; } AVInputFormat ff_aac_demuxer = { diff --git a/libavformat/ac3dec.c b/libavformat/ac3dec.c index e85b0ac7c..6f423ff7e 100644 --- a/libavformat/ac3dec.c +++ b/libavformat/ac3dec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/crc.h" #include "libavcodec/ac3_parser.h" #include "avformat.h" @@ -28,8 +29,6 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) { int max_frames, first_frames = 0, frames; const uint8_t *buf, *buf2, *end; - AC3HeaderInfo *phdr = NULL; - GetBitContext gbc; enum AVCodecID codec_id = AV_CODEC_ID_AC3; max_frames = 0; @@ -44,39 +43,49 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) for(frames = 0; buf2 < end; frames++) { uint8_t buf3[4096]; - int i; - if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) + uint8_t bitstream_id; + uint16_t frame_size; + int i, ret; + + if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) { + if (buf2 + 16 > end) + break; buf2+=16; + } if (buf[0] == 0x77 && buf[1] == 0x0B) { for(i=0; i<8; i+=2) { buf3[i ] = buf2[i+1]; buf3[i+1] = buf2[i ]; } - init_get_bits(&gbc, buf3, 54); + ret = av_ac3_parse_header(buf3, 8, &bitstream_id, + &frame_size); }else - init_get_bits(&gbc, buf2, 54); - if(avpriv_ac3_parse_header(&gbc, &phdr) < 0) + ret = av_ac3_parse_header(buf2, end - buf2, &bitstream_id, + &frame_size); + if (ret < 0) break; - if(buf2 + phdr->frame_size > end) + if(buf2 + frame_size > end) break; if (buf[0] == 0x77 && buf[1] == 0x0B) { - av_assert0(phdr->frame_size <= sizeof(buf3)); - for(i=8; iframe_size; i+=2) { + av_assert0(frame_size <= sizeof(buf3)); + for(i = 8; i < frame_size; i += 2) { buf3[i ] = buf2[i+1]; buf3[i+1] = buf2[i ]; } + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf3 + 2, frame_size - 2)) + break; + } else { + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, frame_size - 2)) + break; } - if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, phdr->frame_size - 2)) - break; - if (phdr->bitstream_id > 10) + if (bitstream_id > 10) codec_id = AV_CODEC_ID_EAC3; - buf2 += phdr->frame_size; + buf2 += frame_size; } max_frames = FFMAX(max_frames, frames); if(buf == p->buf) first_frames = frames; } - av_freep(&phdr); if(codec_id != expected_codec_id) return 0; // keep this in sync with mp3 probe, both need to avoid // issues with MPEG-files! diff --git a/libavformat/adtsenc.c b/libavformat/adtsenc.c index a046c2f2f..a24f99c44 100644 --- a/libavformat/adtsenc.c +++ b/libavformat/adtsenc.c @@ -85,7 +85,7 @@ static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, const ui init_put_bits(&pb, adts->pce_data, MAX_PCE_SIZE); put_bits(&pb, 3, 5); //ID_PCE - adts->pce_size = (avpriv_copy_pce_data(&pb, &gb) + 3) / 8; + adts->pce_size = (ff_copy_pce_data(&pb, &gb) + 3) / 8; flush_put_bits(&pb); } diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c index 99e05c78e..7c701e0c7 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -81,11 +81,10 @@ static void get_meta(AVFormatContext *s, const char *key, int size) av_free(str); return; } - size += (size&1)-res; + size -= res; str[res] = 0; av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL); - }else - size+= size&1; + } avio_skip(s->pb, size); } @@ -325,6 +324,16 @@ static int aiff_read_header(AVFormatContext *s) if(ff_mov_read_chan(s, pb, st, size) < 0) return AVERROR_INVALIDDATA; break; + case MKTAG('A','P','C','M'): /* XA ADPCM compressed sound chunk */ + st->codecpar->codec_id = AV_CODEC_ID_ADPCM_XA; + aiff->data_end = avio_tell(pb) + size; + offset = avio_tell(pb) + 8; + /* This field is unknown and its data seems to be irrelevant */ + avio_rb32(pb); + st->codecpar->block_align = avio_rb32(pb); + + goto got_sound; + break; case 0: if (offset > 0 && st->codecpar->block_align) // COMM && SSND goto got_sound; diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 405ddb5ad..ec8409630 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -63,10 +63,13 @@ static void register_all(void) REGISTER_MUXDEMUX(AIFF, aiff); REGISTER_DEMUXER (AIX, aix); REGISTER_MUXDEMUX(AMR, amr); + REGISTER_DEMUXER (AMRNB, amrnb); + REGISTER_DEMUXER (AMRWB, amrwb); REGISTER_DEMUXER (ANM, anm); REGISTER_DEMUXER (APC, apc); REGISTER_DEMUXER (APE, ape); REGISTER_MUXDEMUX(APNG, apng); + REGISTER_MUXDEMUX(APTX, aptx); REGISTER_DEMUXER (AQTITLE, aqtitle); REGISTER_MUXDEMUX(ASF, asf); REGISTER_DEMUXER (ASF_O, asf_o); @@ -117,7 +120,6 @@ static void register_all(void) REGISTER_MUXDEMUX(EAC3, eac3); REGISTER_DEMUXER (EPAF, epaf); REGISTER_MUXER (F4V, f4v); - REGISTER_MUXDEMUX(FFM, ffm); REGISTER_MUXDEMUX(FFMETADATA, ffmetadata); REGISTER_MUXER (FIFO, fifo); REGISTER_MUXDEMUX(FILMSTRIP, filmstrip); @@ -221,6 +223,7 @@ static void register_all(void) REGISTER_DEMUXER (MXG, mxg); REGISTER_DEMUXER (NC, nc); REGISTER_DEMUXER (NISTSPHERE, nistsphere); + REGISTER_DEMUXER (NSP, nsp); REGISTER_DEMUXER (NSV, nsv); REGISTER_MUXER (NULL, null); REGISTER_MUXDEMUX(NUT, nut); @@ -320,6 +323,7 @@ static void register_all(void) REGISTER_MUXDEMUX(TTA, tta); REGISTER_DEMUXER (TXD, txd); REGISTER_DEMUXER (TTY, tty); + REGISTER_DEMUXER (TY, ty); REGISTER_MUXER (UNCODEDFRAMECRC, uncodedframecrc); REGISTER_DEMUXER (V210, v210); REGISTER_DEMUXER (V210X, v210x); diff --git a/libavformat/amr.c b/libavformat/amr.c index b5194a2d9..8b4d736d2 100644 --- a/libavformat/amr.c +++ b/libavformat/amr.c @@ -38,6 +38,13 @@ typedef struct { static const char AMR_header[] = "#!AMR\n"; static const char AMRWB_header[] = "#!AMR-WB\n"; +static const uint8_t amrnb_packed_size[16] = { + 13, 14, 16, 18, 20, 21, 27, 32, 6, 1, 1, 1, 1, 1, 1, 1 +}; +static const uint8_t amrwb_packed_size[16] = { + 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 1, 1, 1, 1, 1, 1 +}; + #if CONFIG_AMR_MUXER static int amr_write_header(AVFormatContext *s) { @@ -126,17 +133,9 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) mode = (toc >> 3) & 0x0F; if (par->codec_id == AV_CODEC_ID_AMR_NB) { - static const uint8_t packed_size[16] = { - 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 - }; - - size = packed_size[mode] + 1; + size = amrnb_packed_size[mode]; } else if (par->codec_id == AV_CODEC_ID_AMR_WB) { - static const uint8_t packed_size[16] = { - 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1 - }; - - size = packed_size[mode]; + size = amrwb_packed_size[mode]; } if (!size || av_new_packet(pkt, size)) @@ -176,6 +175,118 @@ AVInputFormat ff_amr_demuxer = { }; #endif +#if CONFIG_AMRNB_DEMUXER +static int amrnb_probe(AVProbeData *p) +{ + int mode, i = 0, valid = 0; + const uint8_t *b = p->buf; + + while (i < p->buf_size) { + mode = b[i] >> 3 & 0x0F; + if (mode < 9 && (b[i] & 0x4) == 0x4) { + int last = mode; + int size = amrnb_packed_size[mode]; + while (size--) { + if (b[++i] != last) + break; + last = b[i]; + } + if (size > 0) { + valid++; + i += size; + } + } else { + valid = 0; + i++; + } + } + if (valid > 100) + return AVPROBE_SCORE_EXTENSION / 2 + 1; + return 0; +} + +static int amrnb_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_id = AV_CODEC_ID_AMR_NB; + st->codecpar->sample_rate = 8000; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + avpriv_set_pts_info(st, 64, 1, 8000); + + return 0; +} + +AVInputFormat ff_amrnb_demuxer = { + .name = "amrnb", + .long_name = NULL_IF_CONFIG_SMALL("raw AMR-NB"), + .priv_data_size = sizeof(AMRContext), + .read_probe = amrnb_probe, + .read_header = amrnb_read_header, + .read_packet = amr_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; +#endif + +#if CONFIG_AMRWB_DEMUXER +static int amrwb_probe(AVProbeData *p) +{ + int mode, i = 0, valid = 0; + const uint8_t *b = p->buf; + + while (i < p->buf_size) { + mode = b[i] >> 3 & 0x0F; + if (mode < 10 && (b[i] & 0x4) == 0x4) { + int last = mode; + int size = amrwb_packed_size[mode]; + while (size--) { + if (b[++i] != last) + break; + last = b[i]; + } + if (size > 0) { + valid++; + i += size; + } + } else { + valid = 0; + i++; + } + } + if (valid > 100) + return AVPROBE_SCORE_EXTENSION / 2 - 1; + return 0; +} + +static int amrwb_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_id = AV_CODEC_ID_AMR_WB; + st->codecpar->sample_rate = 16000; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + avpriv_set_pts_info(st, 64, 1, 16000); + + return 0; +} + +AVInputFormat ff_amrwb_demuxer = { + .name = "amrwb", + .long_name = NULL_IF_CONFIG_SMALL("raw AMR-WB"), + .priv_data_size = sizeof(AMRContext), + .read_probe = amrwb_probe, + .read_header = amrwb_read_header, + .read_packet = amr_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; +#endif + #if CONFIG_AMR_MUXER AVOutputFormat ff_amr_muxer = { .name = "amr", diff --git a/libavformat/aptxdec.c b/libavformat/aptxdec.c new file mode 100644 index 000000000..3b8fae1b5 --- /dev/null +++ b/libavformat/aptxdec.c @@ -0,0 +1,78 @@ +/* + * RAW aptX demuxer + * + * Copyright (C) 2017 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 + */ + +#include "avformat.h" +#include "rawdec.h" + +#define APTX_BLOCK_SIZE 4 +#define APTX_PACKET_SIZE (256*APTX_BLOCK_SIZE) + +typedef struct AptXDemuxerContext { + AVClass *class; + int sample_rate; +} AptXDemuxerContext; + +static int aptx_read_header(AVFormatContext *s) +{ + AptXDemuxerContext *s1 = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_APTX; + st->codecpar->format = AV_SAMPLE_FMT_S32P; + st->codecpar->channels = 2; + st->codecpar->sample_rate = s1->sample_rate; + st->codecpar->bits_per_coded_sample = 4; + st->codecpar->block_align = APTX_BLOCK_SIZE; + st->codecpar->frame_size = APTX_PACKET_SIZE; + st->start_time = 0; + return 0; +} + +static int aptx_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + return av_get_packet(s->pb, pkt, APTX_PACKET_SIZE); +} + +static const AVOption aptx_options[] = { + { "sample_rate", "", offsetof(AptXDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass aptx_demuxer_class = { + .class_name = "aptx demuxer", + .item_name = av_default_item_name, + .option = aptx_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_aptx_demuxer = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("raw aptX"), + .extensions = "aptx", + .priv_data_size = sizeof(AptXDemuxerContext), + .read_header = aptx_read_header, + .read_packet = aptx_read_packet, + .flags = AVFMT_GENERIC_INDEX, + .priv_class = &aptx_demuxer_class, +}; diff --git a/libavformat/avc.c b/libavformat/avc.c index 094a95821..ec50033a0 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavcodec/h264.h" #include "avformat.h" #include "avio.h" #include "avc.h" @@ -105,60 +106,92 @@ int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) { - if (len > 6) { - /* check for H.264 start code */ - if (AV_RB32(data) == 0x00000001 || - AV_RB24(data) == 0x000001) { - uint8_t *buf=NULL, *end, *start; - uint32_t sps_size=0, pps_size=0; - uint8_t *sps=0, *pps=0; + AVIOContext *sps_pb = NULL, *pps_pb = NULL; + uint8_t *buf = NULL, *end, *start = NULL; + uint8_t *sps = NULL, *pps = NULL; + uint32_t sps_size = 0, pps_size = 0; + int ret, nb_sps = 0, nb_pps = 0; - int ret = ff_avc_parse_nal_units_buf(data, &buf, &len); - if (ret < 0) - return ret; - start = buf; - end = buf + len; + if (len <= 6) + return AVERROR_INVALIDDATA; - /* look for sps and pps */ - while (end - buf > 4) { - uint32_t size; - uint8_t nal_type; - size = FFMIN(AV_RB32(buf), end - buf - 4); - buf += 4; - nal_type = buf[0] & 0x1f; - - if (nal_type == 7) { /* SPS */ - sps = buf; - sps_size = size; - } else if (nal_type == 8) { /* PPS */ - pps = buf; - pps_size = size; - } - - buf += size; - } - - if (!sps || !pps || sps_size < 4 || sps_size > UINT16_MAX || pps_size > UINT16_MAX) - return AVERROR_INVALIDDATA; - - avio_w8(pb, 1); /* version */ - avio_w8(pb, sps[1]); /* profile */ - avio_w8(pb, sps[2]); /* profile compat */ - avio_w8(pb, sps[3]); /* level */ - avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ - avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ - - avio_wb16(pb, sps_size); - avio_write(pb, sps, sps_size); - avio_w8(pb, 1); /* number of pps */ - avio_wb16(pb, pps_size); - avio_write(pb, pps, pps_size); - av_free(start); - } else { - avio_write(pb, data, len); - } + /* check for H.264 start code */ + if (AV_RB32(data) != 0x00000001 && + AV_RB24(data) != 0x000001) { + avio_write(pb, data, len); + return 0; } - return 0; + + ret = ff_avc_parse_nal_units_buf(data, &buf, &len); + if (ret < 0) + return ret; + start = buf; + end = buf + len; + + ret = avio_open_dyn_buf(&sps_pb); + if (ret < 0) + goto fail; + ret = avio_open_dyn_buf(&pps_pb); + if (ret < 0) + goto fail; + + /* look for sps and pps */ + while (end - buf > 4) { + uint32_t size; + uint8_t nal_type; + size = FFMIN(AV_RB32(buf), end - buf - 4); + buf += 4; + nal_type = buf[0] & 0x1f; + + if (nal_type == 7) { /* SPS */ + nb_sps++; + if (size > UINT16_MAX || nb_sps >= H264_MAX_SPS_COUNT) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_wb16(sps_pb, size); + avio_write(sps_pb, buf, size); + } else if (nal_type == 8) { /* PPS */ + nb_pps++; + if (size > UINT16_MAX || nb_pps >= H264_MAX_PPS_COUNT) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_wb16(pps_pb, size); + avio_write(pps_pb, buf, size); + } + + buf += size; + } + sps_size = avio_close_dyn_buf(sps_pb, &sps); + pps_size = avio_close_dyn_buf(pps_pb, &pps); + + if (sps_size < 6 || !pps_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + avio_w8(pb, 1); /* version */ + avio_w8(pb, sps[3]); /* profile */ + avio_w8(pb, sps[4]); /* profile compat */ + avio_w8(pb, sps[5]); /* level */ + avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ + avio_w8(pb, 0xe0 | nb_sps); /* 3 bits reserved (111) + 5 bits number of sps */ + + avio_write(pb, sps, sps_size); + avio_w8(pb, nb_pps); /* number of pps */ + avio_write(pb, pps, pps_size); + +fail: + if (!sps) + avio_close_dyn_buf(sps_pb, &sps); + if (!pps) + avio_close_dyn_buf(pps_pb, &pps); + av_free(sps); + av_free(pps); + av_free(start); + + return ret; } int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index b0de66ac1..4f2798a87 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -437,19 +437,6 @@ int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); */ int av_append_packet(AVIOContext *s, AVPacket *pkt, int size); -#if FF_API_LAVF_FRAC -/*************************************************/ -/* fractional numbers for exact pts handling */ - -/** - * The exact value of the fractional number is: 'val + num / den'. - * num is assumed to be 0 <= num < den. - */ -typedef struct AVFrac { - int64_t val, num, den; -} AVFrac; -#endif - /*************************************************/ /* input/output formats */ @@ -478,10 +465,6 @@ typedef struct AVProbeData { #define AVFMT_NOFILE 0x0001 #define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */ #define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */ -#if FF_API_LAVF_FMT_RAWPICTURE -#define AVFMT_RAWPICTURE 0x0020 /**< Format wants AVPicture structure for - raw picture data. @deprecated Not used anymore */ -#endif #define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ #define AVFMT_NOTIMESTAMPS 0x0080 /**< Format does not need / have any timestamps. */ #define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */ @@ -802,9 +785,9 @@ enum AVStreamParseType { AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */ AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */ AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */ - AVSTREAM_PARSE_FULL_RAW=MKTAG(0,'R','A','W'), /**< full parsing and repack with timestamp and position generation by parser for raw - this assumes that each packet in the file contains no demuxer level headers and - just codec level data, otherwise position generation would fail */ + AVSTREAM_PARSE_FULL_RAW, /**< full parsing and repack with timestamp and position generation by parser for raw + this assumes that each packet in the file contains no demuxer level headers and + just codec level data, otherwise position generation would fail */ }; typedef struct AVIndexEntry { @@ -894,14 +877,6 @@ typedef struct AVStream { #endif void *priv_data; -#if FF_API_LAVF_FRAC - /** - * @deprecated this field is unused - */ - attribute_deprecated - struct AVFrac pts; -#endif - /** * This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. @@ -1001,6 +976,34 @@ typedef struct AVStream { int event_flags; #define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + /** + * Real base framerate of the stream. + * This is the lowest framerate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * framerates in the stream). Note, this value is just a guess! + * For example, if the time base is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + */ + AVRational r_frame_rate; + + /** + * String containing pairs of key and values describing recommended encoder configuration. + * Pairs are separated by ','. + * Keys are separated from values by '='. + */ + char *recommended_encoder_configuration; + + /** + * Codec parameters associated with this stream. Allocated and freed by + * libavformat in avformat_new_stream() and avformat_free_context() + * respectively. + * + * - demuxing: filled by libavformat on stream creation or in + * avformat_find_stream_info() + * - muxing: filled by the caller before avformat_write_header() + */ + AVCodecParameters *codecpar; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavformat and can be changed and @@ -1023,6 +1026,7 @@ typedef struct AVStream { double (*duration_error)[2][MAX_STD_TIMEBASES]; int64_t codec_info_duration; int64_t codec_info_duration_fields; + int frame_delay_evidence; /** * 0 -> decoder has not been searched for yet. @@ -1085,19 +1089,6 @@ typedef struct AVStream { int nb_index_entries; unsigned int index_entries_allocated_size; - /** - * Real base framerate of the stream. - * This is the lowest framerate with which all timestamps can be - * represented accurately (it is the least common multiple of all - * framerates in the stream). Note, this value is just a guess! - * For example, if the time base is 1/90000 and all frames have either - * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. - * - * Code outside avformat should access this field using: - * av_stream_get/set_r_frame_rate(stream) - */ - AVRational r_frame_rate; - /** * Stream Identifier * This is the MPEG-TS stream identifier +1 @@ -1203,19 +1194,6 @@ typedef struct AVStream { */ int inject_global_side_data; - /***************************************************************** - * All fields above this line are not part of the public API. - * Fields below are part of the public API and ABI again. - ***************************************************************** - */ - - /** - * String containing paris of key and values describing recommended encoder configuration. - * Paris are separated by ','. - * Keys are separated from values by '='. - */ - char *recommended_encoder_configuration; - /** * display aspect ratio (0 if unknown) * - encoding: unused @@ -1223,31 +1201,29 @@ typedef struct AVStream { */ AVRational display_aspect_ratio; - struct FFFrac *priv_pts; - /** * An opaque field for libavformat internal usage. * Must not be accessed in any way by callers. */ AVStreamInternal *internal; - - /* - * Codec parameters associated with this stream. Allocated and freed by - * libavformat in avformat_new_stream() and avformat_free_context() - * respectively. - * - * - demuxing: filled by libavformat on stream creation or in - * avformat_find_stream_info() - * - muxing: filled by the caller before avformat_write_header() - */ - AVCodecParameters *codecpar; } AVStream; +#if FF_API_FORMAT_GET_SET +/** + * Accessors for some AVStream fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +attribute_deprecated AVRational av_stream_get_r_frame_rate(const AVStream *s); +attribute_deprecated void av_stream_set_r_frame_rate(AVStream *s, AVRational r); -struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); +attribute_deprecated char* av_stream_get_recommended_encoder_configuration(const AVStream *s); +attribute_deprecated void av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration); +#endif + +struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); /** * Returns the pts of the last muxed packet + its duration @@ -1469,11 +1445,11 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #if FF_API_LAVF_KEEPSIDE_FLAG -#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. Deprecated, will be the default. +#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Deprecated, does nothing. #endif #define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats #define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops. -#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Wait for packet data before writing a header, and add bitstream filters as requested by the muxer +#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer /** * Maximum size of the data read from input for determining @@ -1919,29 +1895,46 @@ typedef struct AVFormatContext { int max_streams; } AVFormatContext; +#if FF_API_FORMAT_GET_SET /** * Accessors for some AVFormatContext fields. These used to be provided for ABI * compatibility, and do not need to be used anymore. */ +attribute_deprecated int av_format_get_probe_score(const AVFormatContext *s); +attribute_deprecated AVCodec * av_format_get_video_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_video_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated AVCodec * av_format_get_audio_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated AVCodec * av_format_get_data_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_data_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated int av_format_get_metadata_header_padding(const AVFormatContext *s); +attribute_deprecated void av_format_set_metadata_header_padding(AVFormatContext *s, int c); +attribute_deprecated void * av_format_get_opaque(const AVFormatContext *s); +attribute_deprecated void av_format_set_opaque(AVFormatContext *s, void *opaque); +attribute_deprecated av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s); +attribute_deprecated void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback); #if FF_API_OLD_OPEN_CALLBACKS attribute_deprecated AVOpenCallback av_format_get_open_cb(const AVFormatContext *s); attribute_deprecated void av_format_set_open_cb(AVFormatContext *s, AVOpenCallback callback); #endif +#endif /** * This function will cause global side data to be injected in the next packet @@ -2103,13 +2096,8 @@ uint8_t *av_stream_new_side_data(AVStream *stream, * @param size pointer for side information size to store (optional) * @return pointer to data if present or NULL otherwise */ -#if FF_API_NOCONST_GET_SIDE_DATA -uint8_t *av_stream_get_side_data(AVStream *stream, - enum AVPacketSideDataType type, int *size); -#else uint8_t *av_stream_get_side_data(const AVStream *stream, enum AVPacketSideDataType type, int *size); -#endif AVProgram *av_new_program(AVFormatContext *s, int id); diff --git a/libavformat/avidec.c b/libavformat/avidec.c index b8a31dcff..3ff515d49 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -401,10 +401,10 @@ static int avi_extract_stream_metadata(AVFormatContext *s, AVStream *st) // skip 4 byte padding bytestream2_skip(&gb, 4); offset = bytestream2_tell(&gb); - bytestream2_init(&gb, data + offset, data_size - offset); // decode EXIF tags from IFD, AVI is always little-endian - return avpriv_exif_decode_ifd(s, &gb, 1, 0, &st->metadata); + return avpriv_exif_decode_ifd(s, data + offset, data_size - offset, + 1, 0, &st->metadata); break; case MKTAG('C', 'A', 'S', 'I'): avpriv_request_sample(s, "RIFF stream data tag type CASI (%u)", tag); diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 483f5b54b..ac0f04c35 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -501,8 +501,14 @@ static int avi_write_header(AVFormatContext *s) AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational) { par->width, par->height }); - int num, den; + int num, den, fields, i; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); + if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_BB || + par->field_order == AV_FIELD_TB || par->field_order == AV_FIELD_BT) { + fields = 2; // interlaced + } else { + fields = 1; // progressive + } avio_wl32(pb, 0); // video format = unknown avio_wl32(pb, 0); // video standard = unknown @@ -514,17 +520,30 @@ static int avi_write_header(AVFormatContext *s) avio_wl16(pb, num); avio_wl32(pb, par->width); avio_wl32(pb, par->height); - avio_wl32(pb, 1); // progressive FIXME + avio_wl32(pb, fields); // fields per frame - avio_wl32(pb, par->height); - avio_wl32(pb, par->width); - avio_wl32(pb, par->height); - avio_wl32(pb, par->width); - avio_wl32(pb, 0); - avio_wl32(pb, 0); + for (i = 0; i < fields; i++) { + int start_line; + // OpenDML v1.02 is not very specific on what value to use for + // start_line when frame data is not coming from a capturing device, + // so just use 0/1 depending on the field order for interlaced frames + if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_TB) { + start_line = (i == 0) ? 0 : 1; + } else if (par->field_order == AV_FIELD_BB || par->field_order == AV_FIELD_BT) { + start_line = (i == 0) ? 1 : 0; + } else { + start_line = 0; + } - avio_wl32(pb, 0); - avio_wl32(pb, 0); + avio_wl32(pb, par->height / fields); // compressed bitmap height + avio_wl32(pb, par->width); // compressed bitmap width + avio_wl32(pb, par->height / fields); // valid bitmap height + avio_wl32(pb, par->width); // valid bitmap width + avio_wl32(pb, 0); // valid bitmap X offset + avio_wl32(pb, 0); // valid bitmap Y offset + avio_wl32(pb, 0); // valid X offset in T + avio_wl32(pb, start_line); // valid Y start line + } ff_end_tag(pb, vprp); } diff --git a/libavformat/avio.c b/libavformat/avio.c index 64248e098..63e82872f 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -297,7 +297,7 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, return url_alloc_for_protocol(puc, p, filename, flags, int_cb); *puc = NULL; - if (av_strstart(filename, "https:", NULL)) + if (av_strstart(filename, "https:", NULL) || av_strstart(filename, "tls:", NULL)) av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with " "openssl, gnutls " "or securetransport enabled.\n"); @@ -391,8 +391,10 @@ static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf, } av_usleep(1000); } - } else if (ret < 1) - return (ret < 0 && ret != AVERROR_EOF) ? ret : len; + } else if (ret == AVERROR_EOF) + return (len > 0) ? len : AVERROR_EOF; + else if (ret < 0) + return ret; if (ret) { fast_retries = FFMAX(fast_retries, 2); wait_since = 0; @@ -623,13 +625,15 @@ int64_t ffurl_size(URLContext *h) int ffurl_get_file_handle(URLContext *h) { - if (!h->prot->url_get_file_handle) + if (!h || !h->prot || !h->prot->url_get_file_handle) return -1; return h->prot->url_get_file_handle(h); } int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles) { + if (!h || !h->prot) + return AVERROR(ENOSYS); if (!h->prot->url_get_multi_file_handle) { if (!h->prot->url_get_file_handle) return AVERROR(ENOSYS); @@ -645,15 +649,15 @@ int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles) int ffurl_get_short_seek(URLContext *h) { - if (!h->prot->url_get_short_seek) + if (!h || !h->prot || !h->prot->url_get_short_seek) return AVERROR(ENOSYS); return h->prot->url_get_short_seek(h); } int ffurl_shutdown(URLContext *h, int flags) { - if (!h->prot->url_shutdown) - return AVERROR(EINVAL); + if (!h || !h->prot || !h->prot->url_shutdown) + return AVERROR(ENOSYS); return h->prot->url_shutdown(h, flags); } diff --git a/libavformat/avio.h b/libavformat/avio.h index f9c5972ad..75912ce6b 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -236,7 +236,6 @@ typedef struct AVIOContext { int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); int64_t (*seek)(void *opaque, int64_t offset, int whence); int64_t pos; /**< position in the file of the current buffer */ - int must_flush; /**< unused */ int eof_reached; /**< true if eof reached */ int write_flag; /**< true if open for writing */ int max_packet_size; @@ -452,6 +451,8 @@ void avio_free_directory_entry(AVIODirEntry **entry); * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise. * @param opaque An opaque pointer to user-specific data. * @param read_packet A function for refilling the buffer, may be NULL. + * For stream protocols, must never return 0 but rather + * a proper AVERROR code. * @param write_packet A function for writing the buffer contents, may be NULL. * The function may not change the input buffers content. * @param seek A function for seeking to specified byte position, may be NULL. @@ -569,13 +570,6 @@ int64_t avio_size(AVIOContext *s); * @return non zero if and only if end of file */ int avio_feof(AVIOContext *s); -#if FF_API_URL_FEOF -/** - * @deprecated use avio_feof() - */ -attribute_deprecated -int url_feof(AVIOContext *s); -#endif /** @warning Writes up to 4 KiB per call */ int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h index c01835df9..04c1ad515 100644 --- a/libavformat/avio_internal.h +++ b/libavformat/avio_internal.h @@ -132,6 +132,14 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size); */ int ffio_fdopen(AVIOContext **s, URLContext *h); +/** + * Return the URLContext associated with the AVIOContext + * + * @param s IO context + * @return pointer to URLContext or NULL. + */ +URLContext *ffio_geturlcontext(AVIOContext *s); + /** * Open a write-only fake memory stream. The written data is not stored * anywhere - this is only used for measuring the amount of data diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 636cb4616..86eb6579f 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -364,13 +364,6 @@ int avio_feof(AVIOContext *s) return s->eof_reached; } -#if FF_API_URL_FEOF -int url_feof(AVIOContext *s) -{ - return avio_feof(s); -} -#endif - void avio_wl32(AVIOContext *s, unsigned int val) { avio_w8(s, (uint8_t) val ); @@ -531,6 +524,24 @@ void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType typ s->last_time = time; } +static int read_packet_wrapper(AVIOContext *s, uint8_t *buf, int size) +{ + int ret; + + if (!s->read_packet) + return AVERROR(EINVAL); + ret = s->read_packet(s->opaque, buf, size); +#if FF_API_OLD_AVIO_EOF_0 + if (!ret && !s->max_packet_size) { + av_log(NULL, AV_LOG_WARNING, "Invalid return value 0 for stream protocol\n"); + ret = AVERROR_EOF; + } +#else + av_assert2(ret || s->max_packet_size); +#endif + return ret; +} + /* Input stream */ static void fill_buffer(AVIOContext *s) @@ -569,16 +580,14 @@ static void fill_buffer(AVIOContext *s) len = s->orig_buffer_size; } - if (s->read_packet) - len = s->read_packet(s->opaque, dst, len); - else - len = 0; - if (len <= 0) { + len = read_packet_wrapper(s, dst, len); + if (len == AVERROR_EOF) { /* do not modify buffer if EOF reached so that a seek back can be done without rereading data */ s->eof_reached = 1; - if (len < 0) - s->error = len; + } else if (len < 0) { + s->eof_reached = 1; + s->error= len; } else { s->pos += len; s->buf_ptr = dst; @@ -644,15 +653,15 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size) if (len == 0 || s->write_flag) { if((s->direct || size > s->buffer_size) && !s->update_checksum) { // bypass the buffer and read data directly into buf - if(s->read_packet) - len = s->read_packet(s->opaque, buf, size); - - if (len <= 0) { + len = read_packet_wrapper(s, buf, size); + if (len == AVERROR_EOF) { /* do not modify buffer if EOF reached so that a seek back can be done without rereading data */ s->eof_reached = 1; - if(len<0) - s->error= len; + break; + } else if (len < 0) { + s->eof_reached = 1; + s->error= len; break; } else { s->pos += len; @@ -711,7 +720,7 @@ int avio_read_partial(AVIOContext *s, unsigned char *buf, int size) return -1; if (s->read_packet && s->write_flag) { - len = s->read_packet(s->opaque, buf, size); + len = read_packet_wrapper(s, buf, size); if (len > 0) s->pos += len; return len; @@ -971,6 +980,19 @@ fail: return AVERROR(ENOMEM); } +URLContext* ffio_geturlcontext(AVIOContext *s) +{ + AVIOInternal *internal; + if (!s) + return NULL; + + internal = s->opaque; + if (internal && s->read_packet == io_read_packet) + return internal->h; + else + return NULL; +} + int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size) { uint8_t *buffer; diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c index 56700288f..250a48932 100644 --- a/libavformat/avisynth.c +++ b/libavformat/avisynth.c @@ -774,15 +774,15 @@ static av_cold int avisynth_read_header(AVFormatContext *s) int ret; // Calling library must implement a lock for thread-safe opens. - if (ret = avpriv_lock_avformat()) + if (ret = ff_lock_avformat()) return ret; if (ret = avisynth_open_file(s)) { - avpriv_unlock_avformat(); + ff_unlock_avformat(); return ret; } - avpriv_unlock_avformat(); + ff_unlock_avformat(); return 0; } @@ -818,11 +818,11 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) static av_cold int avisynth_read_close(AVFormatContext *s) { - if (avpriv_lock_avformat()) + if (ff_lock_avformat()) return AVERROR_UNKNOWN; avisynth_context_destroy(s->priv_data); - avpriv_unlock_avformat(); + ff_unlock_avformat(); return 0; } diff --git a/libavformat/cache.c b/libavformat/cache.c index 6aabca2e7..66bbbf54c 100644 --- a/libavformat/cache.c +++ b/libavformat/cache.c @@ -201,7 +201,7 @@ static int cache_read(URLContext *h, unsigned char *buf, int size) } r = ffurl_read(c->inner, buf, size); - if (r == 0 && size>0) { + if (r == AVERROR_EOF && size>0) { c->is_true_eof = 1; av_assert0(c->end >= c->logical_pos); } @@ -263,7 +263,7 @@ resolve_eof: if (whence == SEEK_SET) size = FFMIN(sizeof(tmp), pos - c->logical_pos); ret = cache_read(h, tmp, size); - if (ret == 0 && whence == SEEK_END) { + if (ret == AVERROR_EOF && whence == SEEK_END) { av_assert0(c->is_true_eof); goto resolve_eof; } diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c index f550cd965..0f7c4ebbb 100644 --- a/libavformat/cafenc.c +++ b/libavformat/cafenc.c @@ -81,6 +81,8 @@ static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels, int bl return 320; case AV_CODEC_ID_MP1: return 384; + case AV_CODEC_ID_OPUS: + return 960; case AV_CODEC_ID_MP2: case AV_CODEC_ID_MP3: return 1152; @@ -117,11 +119,15 @@ static int caf_write_header(AVFormatContext *s) switch (par->codec_id) { case AV_CODEC_ID_AAC: - case AV_CODEC_ID_OPUS: av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n"); return AVERROR_PATCHWELCOME; } + if (par->codec_id == AV_CODEC_ID_OPUS && par->channels > 2) { + av_log(s, AV_LOG_ERROR, "Only mono and stereo are supported for Opus\n"); + return AVERROR_INVALIDDATA; + } + if (!codec_tag) { av_log(s, AV_LOG_ERROR, "unsupported codec\n"); return AVERROR_INVALIDDATA; diff --git a/libavformat/chromaprint.c b/libavformat/chromaprint.c index 4da02bef7..f39c09ddb 100644 --- a/libavformat/chromaprint.c +++ b/libavformat/chromaprint.c @@ -20,6 +20,7 @@ */ #include "avformat.h" +#include "internal.h" #include "libavutil/opt.h" #include "libavcodec/internal.h" #include @@ -49,9 +50,9 @@ typedef struct ChromaprintMuxContext { static void cleanup(ChromaprintMuxContext *cpr) { if (cpr->ctx) { - avpriv_lock_avformat(); + ff_lock_avformat(); chromaprint_free(cpr->ctx); - avpriv_unlock_avformat(); + ff_unlock_avformat(); } } @@ -60,9 +61,9 @@ static int write_header(AVFormatContext *s) ChromaprintMuxContext *cpr = s->priv_data; AVStream *st; - avpriv_lock_avformat(); + ff_lock_avformat(); cpr->ctx = chromaprint_new(cpr->algorithm); - avpriv_unlock_avformat(); + ff_unlock_avformat(); if (!cpr->ctx) { av_log(s, AV_LOG_ERROR, "Failed to create chromaprint context.\n"); diff --git a/libavformat/concat.c b/libavformat/concat.c index 46b520fe8..19c83c309 100644 --- a/libavformat/concat.c +++ b/libavformat/concat.c @@ -135,19 +135,20 @@ static int concat_read(URLContext *h, unsigned char *buf, int size) while (size > 0) { result = ffurl_read(nodes[i].uc, buf, size); - if (result < 0) - return total ? total : result; - if (!result) { + if (result == AVERROR_EOF) { if (i + 1 == data->length || ffurl_seek(nodes[++i].uc, 0, SEEK_SET) < 0) break; + result = 0; } + if (result < 0) + return total ? total : result; total += result; buf += result; size -= result; } data->current = i; - return total; + return total ? total : result; } static int64_t concat_seek(URLContext *h, int64_t pos, int whence) diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index 0e189012a..bd5174ada 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -185,8 +185,8 @@ static int copy_stream_props(AVStream *st, AVStream *source_st) return ret; st->r_frame_rate = source_st->r_frame_rate; st->avg_frame_rate = source_st->avg_frame_rate; - st->time_base = source_st->time_base; st->sample_aspect_ratio = source_st->sample_aspect_ratio; + avpriv_set_pts_info(st, 64, source_st->time_base.num, source_st->time_base.den); av_dict_copy(&st->metadata, source_st->metadata, 0); return 0; diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index f63f1fffb..0e3afd2a3 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -328,17 +328,17 @@ static void free_representation(struct representation *pls) } av_freep(&pls->url_template); - av_freep(pls); + av_freep(&pls); } -static void set_httpheader_options(DASHContext *c, AVDictionary *opts) +static void set_httpheader_options(DASHContext *c, AVDictionary **opts) { // broker prior HTTP options that should be consistent across requests - av_dict_set(&opts, "user-agent", c->user_agent, 0); - av_dict_set(&opts, "cookies", c->cookies, 0); - av_dict_set(&opts, "headers", c->headers, 0); + av_dict_set(opts, "user-agent", c->user_agent, 0); + av_dict_set(opts, "cookies", c->cookies, 0); + av_dict_set(opts, "headers", c->headers, 0); if (c->is_live) { - av_dict_set(&opts, "seekable", "0", 0); + av_dict_set(opts, "seekable", "0", 0); } } static void update_options(char **dest, const char *name, void *src) @@ -885,7 +885,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) if (!in) { close_in = 1; - set_httpheader_options(c, opts); + set_httpheader_options(c, &opts); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); av_dict_free(&opts); if (ret < 0) @@ -1079,9 +1079,8 @@ static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls) return num; } -static int64_t calc_max_seg_no(struct representation *pls) +static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c) { - DASHContext *c = pls->parent->priv_data; int64_t num = 0; if (pls->n_fragments) { @@ -1101,21 +1100,21 @@ static int64_t calc_max_seg_no(struct representation *pls) return num; } -static void move_timelines(struct representation *rep_src, struct representation *rep_dest) +static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) { if (rep_dest && rep_src ) { free_timelines_list(rep_dest); rep_dest->timelines = rep_src->timelines; rep_dest->n_timelines = rep_src->n_timelines; rep_dest->first_seq_no = rep_src->first_seq_no; - rep_dest->last_seq_no = calc_max_seg_no(rep_dest); + rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); rep_src->timelines = NULL; rep_src->n_timelines = 0; rep_dest->cur_seq_no = rep_src->cur_seq_no; } } -static void move_segments(struct representation *rep_src, struct representation *rep_dest) +static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) { if (rep_dest && rep_src ) { free_fragment_list(rep_dest); @@ -1126,7 +1125,7 @@ static void move_segments(struct representation *rep_src, struct representation rep_dest->fragments = rep_src->fragments; rep_dest->n_fragments = rep_src->n_fragments; rep_dest->parent = rep_src->parent; - rep_dest->last_seq_no = calc_max_seg_no(rep_dest); + rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); rep_src->fragments = NULL; rep_src->n_fragments = 0; } @@ -1163,21 +1162,21 @@ static int refresh_manifest(AVFormatContext *s) if (cur_video && cur_video->timelines) { c->cur_video->cur_seq_no = calc_next_seg_no_from_timelines(c->cur_video, currentVideoTime * cur_video->fragment_timescale - 1); if (c->cur_video->cur_seq_no >= 0) { - move_timelines(c->cur_video, cur_video); + move_timelines(c->cur_video, cur_video, c); } } if (cur_audio && cur_audio->timelines) { c->cur_audio->cur_seq_no = calc_next_seg_no_from_timelines(c->cur_audio, currentAudioTime * cur_audio->fragment_timescale - 1); if (c->cur_audio->cur_seq_no >= 0) { - move_timelines(c->cur_audio, cur_audio); + move_timelines(c->cur_audio, cur_audio, c); } } } if (cur_video && cur_video->fragments) { - move_segments(c->cur_video, cur_video); + move_segments(c->cur_video, cur_video, c); } if (cur_audio && cur_audio->fragments) { - move_segments(c->cur_audio, cur_audio); + move_segments(c->cur_audio, cur_audio, c); } finish: @@ -1226,7 +1225,7 @@ static struct fragment *get_current_fragment(struct representation *pls) } if (c->is_live) { min_seq_no = calc_min_seg_no(pls->parent, pls); - max_seq_no = calc_max_seg_no(pls); + max_seq_no = calc_max_seg_no(pls, c); if (pls->timelines || pls->fragments) { refresh_manifest(pls->parent); @@ -1302,7 +1301,7 @@ static int open_input(DASHContext *c, struct representation *pls, struct fragmen char url[MAX_URL_SIZE]; int ret; - set_httpheader_options(c, opts); + set_httpheader_options(c, &opts); if (seg->size >= 0) { /* try to restrict the HTTP request to the part we want * (if this is in fact a HTTP request) */ @@ -1466,8 +1465,12 @@ static int save_avio_options(AVFormatContext *s) if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { if (buf[0] != '\0') { ret = av_dict_set(&c->avio_opts, *opt, buf, AV_DICT_DONT_STRDUP_VAL); - if (ret < 0) + if (ret < 0) { + av_freep(&buf); return ret; + } + } else { + av_freep(&buf); } } opt++; @@ -1560,7 +1563,7 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p pls->parent = s; pls->cur_seq_no = calc_cur_seg_no(s, pls); - pls->last_seq_no = calc_max_seg_no(pls); + pls->last_seq_no = calc_max_seg_no(pls, s->priv_data); ret = reopen_demux_for_component(s, pls); if (ret < 0) { diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 240ff4138..3345b8911 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -36,6 +36,10 @@ #include "avc.h" #include "avformat.h" #include "avio_internal.h" +#include "hlsplaylist.h" +#if CONFIG_HTTP_PROTOCOL +#include "http.h" +#endif #include "internal.h" #include "isom.h" #include "os_support.h" @@ -55,6 +59,8 @@ typedef struct AdaptationSet { char id[10]; enum AVMediaType media_type; AVDictionary *metadata; + AVRational min_frame_rate, max_frame_rate; + int ambiguous_frame_rate; } AdaptationSet; typedef struct OutputStream { @@ -97,9 +103,13 @@ typedef struct DASHContext { const char *single_file_name; const char *init_seg_name; const char *media_seg_name; - AVRational min_frame_rate, max_frame_rate; - int ambiguous_frame_rate; const char *utc_timing_url; + const char *user_agent; + int hls_playlist; + int http_persistent; + int master_playlist_created; + AVIOContext *mpd_out; + AVIOContext *m3u8_out; } DASHContext; static struct codec_string { @@ -113,6 +123,36 @@ static struct codec_string { { 0, NULL } }; +static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, + AVDictionary **options) { + DASHContext *c = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + int err = AVERROR_MUXER_NOT_FOUND; + if (!*pb || !http_base_proto || !c->http_persistent) { + err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + err = ff_http_do_new_request(http_url_context, filename); +#endif + } + return err; +} + +static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) { + DASHContext *c = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + + if (!http_base_proto || !c->http_persistent) { + ff_format_io_close(s, pb); +#if CONFIG_HTTP_PROTOCOL + } else { + avio_flush(*pb); +#endif + } +} + static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, char *str, int size) { @@ -210,6 +250,22 @@ static int flush_dynbuf(OutputStream *os, int *range_length) return avio_open_dyn_buf(&os->ctx->pb); } +static void set_http_options(AVDictionary **options, DASHContext *c) +{ + if (c->user_agent) + av_dict_set(options, "user_agent", c->user_agent, 0); + if (c->http_persistent) + av_dict_set_int(options, "multiple_requests", 1, 0); +} + +static void get_hls_playlist_name(char *playlist_name, int string_size, + const char *base_url, int id) { + if (base_url) + snprintf(playlist_name, string_size, "%smedia_%d.m3u8", base_url, id); + else + snprintf(playlist_name, string_size, "media_%d.m3u8", id); +} + static int flush_init_segment(AVFormatContext *s, OutputStream *os) { DASHContext *c = s->priv_data; @@ -255,8 +311,10 @@ static void dash_free(AVFormatContext *s) av_freep(&c->streams); } -static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext *c) +static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatContext *s, + int representation_id, int final) { + DASHContext *c = s->priv_data; int i, start_index = 0, start_number = 1; if (c->window_size) { start_index = FFMAX(os->nb_segments - c->window_size, 0); @@ -315,6 +373,61 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext } avio_printf(out, "\t\t\t\t\n"); } + if (c->hls_playlist && start_index < os->nb_segments) + { + int timescale = os->ctx->streams[0]->time_base.den; + char temp_filename_hls[1024]; + char filename_hls[1024]; + AVDictionary *http_opts = NULL; + int target_duration = 0; + int ret = 0; + const char *proto = avio_find_protocol_name(c->dirname); + int use_rename = proto && !strcmp(proto, "file"); + + get_hls_playlist_name(filename_hls, sizeof(filename_hls), + c->dirname, representation_id); + + snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? "%s.tmp" : "%s", filename_hls); + + set_http_options(&http_opts, c); + dashenc_io_open(s, &c->m3u8_out, temp_filename_hls, &http_opts); + av_dict_free(&http_opts); + for (i = start_index; i < os->nb_segments; i++) { + Segment *seg = os->segments[i]; + double duration = (double) seg->duration / timescale; + if (target_duration <= duration) + target_duration = lrint(duration); + } + + ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration, + start_number, PLAYLIST_TYPE_NONE); + + ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file, + os->init_range_length, os->init_start_pos); + + for (i = start_index; i < os->nb_segments; i++) { + Segment *seg = os->segments[i]; + ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file, + (double) seg->duration / timescale, 0, + seg->range_length, seg->start_pos, NULL, + c->single_file ? os->initfile : seg->file, + NULL); + if (ret < 0) { + av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); + } + } + + if (final) + ff_hls_write_end_list(c->m3u8_out); + + dashenc_io_close(s, &c->m3u8_out, temp_filename_hls); + + if (use_rename) + if (avpriv_io_move(temp_filename_hls, filename_hls) < 0) { + av_log(os->ctx, AV_LOG_WARNING, "renaming file %s to %s failed\n\n", temp_filename_hls, filename_hls); + } + } + } static char *xmlescape(const char *str) { @@ -384,7 +497,8 @@ static void format_date_now(char *buf, int size) } } -static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index) +static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index, + int final) { DASHContext *c = s->priv_data; AdaptationSet *as = &c->as[as_index]; @@ -393,8 +507,8 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind avio_printf(out, "\t\tid, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); - if (as->media_type == AVMEDIA_TYPE_VIDEO && c->max_frame_rate.num && !c->ambiguous_frame_rate) - avio_printf(out, " %s=\"%d/%d\"", (av_cmp_q(c->min_frame_rate, c->max_frame_rate) < 0) ? "maxFrameRate" : "frameRate", c->max_frame_rate.num, c->max_frame_rate.den); + if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0) + avio_printf(out, " maxFrameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den); lang = av_dict_get(as->metadata, "language", NULL, 0); if (lang) avio_printf(out, " lang=\"%s\"", lang->value); @@ -423,7 +537,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind avio_printf(out, "\t\t\t\t\n", s->streams[i]->codecpar->channels); } - output_segment_list(os, out, c); + output_segment_list(os, out, s, i, final); avio_printf(out, "\t\t\t\n"); } avio_printf(out, "\t\t\n"); @@ -575,16 +689,20 @@ static int write_manifest(AVFormatContext *s, int final) int use_rename = proto && !strcmp(proto, "file"); static unsigned int warned_non_file = 0; AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0); + AVDictionary *opts = NULL; if (!use_rename && !warned_non_file++) av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename); - ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL); + set_http_options(&opts, c); + ret = dashenc_io_open(s, &c->mpd_out, temp_filename, &opts); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); return ret; } + out = c->mpd_out; + av_dict_free(&opts); avio_printf(out, "\n"); avio_printf(out, "\n"); - if (c->utc_timing_url) - avio_printf(out, "\t\n", c->utc_timing_url); if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) { OutputStream *os = &c->streams[0]; @@ -642,16 +758,76 @@ static int write_manifest(AVFormatContext *s, int final) } for (i = 0; i < c->nb_as; i++) { - if ((ret = write_adaptation_set(s, out, i)) < 0) + if ((ret = write_adaptation_set(s, out, i, final)) < 0) return ret; } avio_printf(out, "\t\n"); + + if (c->utc_timing_url) + avio_printf(out, "\t\n", c->utc_timing_url); + avio_printf(out, "\n"); avio_flush(out); - ff_format_io_close(s, &out); + dashenc_io_close(s, &c->mpd_out, temp_filename); - if (use_rename) - return avpriv_io_move(temp_filename, s->filename); + if (use_rename) { + if ((ret = avpriv_io_move(temp_filename, s->filename)) < 0) + return ret; + } + + if (c->hls_playlist && !c->master_playlist_created) { + char filename_hls[1024]; + const char *audio_group = "A1"; + int is_default = 1; + int max_audio_bitrate = 0; + + if (*c->dirname) + snprintf(filename_hls, sizeof(filename_hls), "%s/master.m3u8", c->dirname); + else + snprintf(filename_hls, sizeof(filename_hls), "master.m3u8"); + + snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", filename_hls); + + set_http_options(&opts, c); + ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, NULL, &opts); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); + return ret; + } + av_dict_free(&opts); + + ff_hls_write_playlist_version(out, 6); + + for (i = 0; i < s->nb_streams; i++) { + char playlist_file[64]; + AVStream *st = s->streams[i]; + if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) + continue; + get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); + ff_hls_write_audio_rendition(out, (char *)audio_group, + playlist_file, i, is_default); + max_audio_bitrate = FFMAX(st->codecpar->bit_rate, max_audio_bitrate); + is_default = 0; + } + + for (i = 0; i < s->nb_streams; i++) { + char playlist_file[64]; + AVStream *st = s->streams[i]; + char *agroup = NULL; + int stream_bitrate = st->codecpar->bit_rate; + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && max_audio_bitrate) { + agroup = (char *)audio_group; + stream_bitrate += max_audio_bitrate; + } + get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); + ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, agroup); + } + avio_close(out); + if (use_rename) + if ((ret = avpriv_io_move(temp_filename, filename_hls)) < 0) + return ret; + c->master_playlist_created = 1; + } return 0; } @@ -664,14 +840,6 @@ static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const ch return 0; } -static int 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 dash_init(AVFormatContext *s) { DASHContext *c = s->priv_data; @@ -683,7 +851,6 @@ static int dash_init(AVFormatContext *s) c->single_file = 1; if (c->single_file) c->use_template = 0; - c->ambiguous_frame_rate = 0; av_strlcpy(c->dirname, s->filename, sizeof(c->dirname)); ptr = strrchr(c->dirname, '/'); @@ -759,6 +926,7 @@ static int dash_init(AVFormatContext *s) avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; st->time_base = s->streams[i]->time_base; + st->avg_frame_rate = s->streams[i]->avg_frame_rate; ctx->avoid_negative_ts = s->avoid_negative_ts; ctx->flags = s->flags; @@ -774,18 +942,23 @@ static int dash_init(AVFormatContext *s) ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->init_seg_name, i, 0, os->bit_rate, 0); } snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile); - ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, NULL); + set_http_options(&opts, c); + ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, &opts); if (ret < 0) return ret; + av_dict_free(&opts); os->init_start_pos = 0; if (!strcmp(os->format_name, "mp4")) { av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); } else { - dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0); - dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit + av_dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0); + av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit + av_dict_set_int(&opts, "dash", 1, 0); + av_dict_set_int(&opts, "dash_track_number", i + 1, 0); + av_dict_set_int(&opts, "live", 1, 0); } - if ((ret = avformat_write_header(ctx, &opts)) < 0) + if ((ret = avformat_init_output(ctx, &opts)) < 0) return ret; os->ctx_inited = 1; avio_flush(ctx->pb); @@ -808,12 +981,12 @@ static int dash_init(AVFormatContext *s) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { AVRational avg_frame_rate = s->streams[i]->avg_frame_rate; if (avg_frame_rate.num > 0) { - if (av_cmp_q(avg_frame_rate, c->min_frame_rate) < 0) - c->min_frame_rate = avg_frame_rate; - if (av_cmp_q(c->max_frame_rate, avg_frame_rate) < 0) - c->max_frame_rate = avg_frame_rate; + if (av_cmp_q(avg_frame_rate, as->min_frame_rate) < 0) + as->min_frame_rate = avg_frame_rate; + if (av_cmp_q(as->max_frame_rate, avg_frame_rate) < 0) + as->max_frame_rate = avg_frame_rate; } else { - c->ambiguous_frame_rate = 1; + as->ambiguous_frame_rate = 1; } c->has_video = 1; } @@ -953,6 +1126,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; + AVStream *st = s->streams[i]; char filename[1024] = "", full_path[1024], temp_path[1024]; int range_length, index_length = 0; @@ -976,12 +1150,15 @@ static int dash_flush(AVFormatContext *s, int final, int stream) } if (!c->single_file) { + AVDictionary *opts = NULL; ff_dash_fill_tmpl_params(filename, sizeof(filename), c->media_seg_name, i, os->segment_index, os->bit_rate, os->start_pts); snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, filename); snprintf(temp_path, sizeof(temp_path), use_rename ? "%s.tmp" : "%s", full_path); - ret = s->io_open(s, &os->out, temp_path, AVIO_FLAG_WRITE, NULL); + set_http_options(&opts, c); + ret = dashenc_io_open(s, &os->out, temp_path, &opts); if (ret < 0) break; + av_dict_free(&opts); if (!strcmp(os->format_name, "mp4")) write_styp(os->ctx->pb); } else { @@ -996,7 +1173,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) if (c->single_file) { find_index_range(s, full_path, os->pos, &index_length); } else { - ff_format_io_close(s, &os->out); + dashenc_io_close(s, &os->out, temp_path); if (use_rename) { ret = avpriv_io_move(temp_path, full_path); @@ -1007,7 +1184,9 @@ static int dash_flush(AVFormatContext *s, int final, int stream) if (!os->bit_rate) { // calculate average bitrate of first segment - int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / (os->max_pts - os->start_pts); + int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts, + st->time_base, + AV_TIME_BASE_Q); if (bitrate >= 0) { os->bit_rate = bitrate; snprintf(os->bandwidth_str, sizeof(os->bandwidth_str), @@ -1181,7 +1360,7 @@ static const AVOption options[] = { { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E }, { "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E }, - { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E }, + { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E }, { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, @@ -1190,6 +1369,9 @@ static const AVOption options[] = { { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.m4s"}, 0, 0, E }, { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.m4s"}, 0, 0, E }, { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, E }, + { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { NULL }, }; @@ -1203,6 +1385,7 @@ static const AVClass dash_class = { AVOutputFormat ff_dash_muxer = { .name = "dash", .long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"), + .extensions = "mpd", .priv_data_size = sizeof(DASHContext), .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_H264, diff --git a/libavformat/dump.c b/libavformat/dump.c index 77043e3fd..ef143fd4e 100644 --- a/libavformat/dump.c +++ b/libavformat/dump.c @@ -372,7 +372,9 @@ static void dump_spherical(void *ctx, AVCodecParameters *par, AVPacketSideData * size_t l, t, r, b; av_spherical_tile_bounds(spherical, par->width, par->height, &l, &t, &r, &b); - av_log(ctx, AV_LOG_INFO, "[%zu, %zu, %zu, %zu] ", l, t, r, b); + av_log(ctx, AV_LOG_INFO, + "[%"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER"] ", + l, t, r, b); } else if (spherical->projection == AV_SPHERICAL_CUBEMAP) { av_log(ctx, AV_LOG_INFO, "[pad %"PRIu32"] ", spherical->padding); } diff --git a/libavformat/ffm.h b/libavformat/ffm.h deleted file mode 100644 index c445f472f..000000000 --- a/libavformat/ffm.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * FFM (ffserver live feed) common header - * 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 AVFORMAT_FFM_H -#define AVFORMAT_FFM_H - -#include -#include "avformat.h" -#include "avio.h" - -/* The FFM file is made of blocks of fixed size */ -#define FFM_HEADER_SIZE 14 -#define FFM_PACKET_SIZE 4096 -#define PACKET_ID 0x666d - -/* each packet contains frames (which can span several packets */ -#define FRAME_HEADER_SIZE 16 -#define FLAG_KEY_FRAME 0x01 -#define FLAG_DTS 0x02 - -enum { - READ_HEADER, - READ_DATA, -}; - -typedef struct FFMContext { - const AVClass *class; - /* only reading mode */ - int64_t write_index, file_size; - int read_state; - uint8_t header[FRAME_HEADER_SIZE+4]; - - /* read and write */ - int first_packet; /* true if first packet, needed to set the discontinuity tag */ - int packet_size; - int frame_offset; - int64_t dts; - uint8_t *packet_ptr, *packet_end; - uint8_t packet[FFM_PACKET_SIZE]; - int64_t start_time; - int server_attached; -} FFMContext; - -#endif /* AVFORMAT_FFM_H */ diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c deleted file mode 100644 index de6ac2725..000000000 --- a/libavformat/ffmdec.c +++ /dev/null @@ -1,878 +0,0 @@ -/* - * FFM (ffserver live feed) demuxer - * 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 - */ - -#include - -#include "libavutil/imgutils.h" -#include "libavutil/internal.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/intfloat.h" -#include "libavutil/opt.h" -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" -#include "libavutil/pixdesc.h" -#include "libavcodec/internal.h" -#include "avformat.h" -#include "internal.h" -#include "ffm.h" -#include "avio_internal.h" - -static int ffm_is_avail_data(AVFormatContext *s, int size) -{ - FFMContext *ffm = s->priv_data; - int64_t pos, avail_size; - ptrdiff_t len; - - len = ffm->packet_end - ffm->packet_ptr; - if (size <= len) - return 1; - pos = avio_tell(s->pb); - if (!ffm->write_index) { - if (pos == ffm->file_size) - return AVERROR_EOF; - avail_size = ffm->file_size - pos; - } else { - if (pos == ffm->write_index) { - /* exactly at the end of stream */ - if (ffm->server_attached) - return AVERROR(EAGAIN); - else - return AVERROR_INVALIDDATA; - } else if (pos < ffm->write_index) { - avail_size = ffm->write_index - pos; - } else { - avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE); - } - } - avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len; - if (size <= avail_size) - return 1; - else if (ffm->server_attached) - return AVERROR(EAGAIN); - else - return AVERROR_INVALIDDATA; -} - -static int ffm_resync(AVFormatContext *s, uint32_t state) -{ - av_log(s, AV_LOG_ERROR, "resyncing\n"); - while (state != PACKET_ID) { - if (avio_feof(s->pb)) { - av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); - return -1; - } - state = (state << 8) | avio_r8(s->pb); - } - return 0; -} - -/* first is true if we read the frame header */ -static int ffm_read_data(AVFormatContext *s, - uint8_t *buf, int size, int header) -{ - FFMContext *ffm = s->priv_data; - AVIOContext *pb = s->pb; - int fill_size, size1, frame_offset; - uint32_t id; - ptrdiff_t len; - int64_t last_pos = -1; - - size1 = size; - while (size > 0) { - redo: - len = ffm->packet_end - ffm->packet_ptr; - if (len < 0) - return -1; - if (len > size) - len = size; - if (len == 0) { - if (avio_tell(pb) == ffm->file_size) { - if (ffm->server_attached) { - avio_seek(pb, ffm->packet_size, SEEK_SET); - } else - return AVERROR_EOF; - } - retry_read: - if (pb->buffer_size != ffm->packet_size) { - int64_t tell = avio_tell(pb); - int ret = ffio_set_buf_size(pb, ffm->packet_size); - if (ret < 0) - return ret; - avio_seek(pb, tell, SEEK_SET); - } - id = avio_rb16(pb); /* PACKET_ID */ - if (id != PACKET_ID) { - if (ffm_resync(s, id) < 0) - return -1; - last_pos = avio_tell(pb); - } - fill_size = avio_rb16(pb); - ffm->dts = avio_rb64(pb); - frame_offset = avio_rb16(pb); - avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE); - if (ffm->packet_size < FFM_HEADER_SIZE + fill_size || frame_offset < 0) { - return -1; - } - ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size); - /* if first packet or resynchronization packet, we must - handle it specifically */ - if (ffm->first_packet || (frame_offset & 0x8000)) { - if (!frame_offset) { - /* This packet has no frame headers in it */ - if (avio_tell(pb) >= ffm->packet_size * 3LL) { - int64_t seekback = FFMIN(ffm->packet_size * 2LL, avio_tell(pb) - last_pos); - seekback = FFMAX(seekback, 0); - avio_seek(pb, -seekback, SEEK_CUR); - goto retry_read; - } - /* This is bad, we cannot find a valid frame header */ - return 0; - } - ffm->first_packet = 0; - if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE) { - ffm->packet_end = ffm->packet_ptr; - return -1; - } - ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; - if (!header) - break; - } else { - ffm->packet_ptr = ffm->packet; - } - goto redo; - } - memcpy(buf, ffm->packet_ptr, len); - buf += len; - ffm->packet_ptr += len; - size -= len; - header = 0; - } - return size1 - size; -} - -/* ensure that actual seeking happens between FFM_PACKET_SIZE - and file_size - FFM_PACKET_SIZE */ -static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1) -{ - FFMContext *ffm = s->priv_data; - AVIOContext *pb = s->pb; - int64_t pos; - - pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); - pos = FFMAX(pos, FFM_PACKET_SIZE); - ff_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); - return avio_seek(pb, pos, SEEK_SET); -} - -static int64_t get_dts(AVFormatContext *s, int64_t pos) -{ - AVIOContext *pb = s->pb; - int64_t dts; - - ffm_seek1(s, pos); - avio_skip(pb, 4); - dts = avio_rb64(pb); - ff_dlog(s, "dts=%0.6f\n", dts / 1000000.0); - return dts; -} - -static void adjust_write_index(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVIOContext *pb = s->pb; - int64_t pts; - //int64_t orig_write_index = ffm->write_index; - int64_t pos_min, pos_max; - int64_t pts_start; - int64_t ptr = avio_tell(pb); - - - pos_min = 0; - pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; - - pts_start = get_dts(s, pos_min); - - pts = get_dts(s, pos_max); - - if (pts - 100000 > pts_start) - goto end; - - ffm->write_index = FFM_PACKET_SIZE; - - pts_start = get_dts(s, pos_min); - - pts = get_dts(s, pos_max); - - if (pts - 100000 <= pts_start) { - while (1) { - int64_t newpos; - int64_t newpts; - - newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE; - - if (newpos == pos_min) - break; - - newpts = get_dts(s, newpos); - - if (newpts - 100000 <= pts) { - pos_max = newpos; - pts = newpts; - } else { - pos_min = newpos; - } - } - ffm->write_index += pos_max; - } - - end: - avio_seek(pb, ptr, SEEK_SET); -} - - -static int ffm_append_recommended_configuration(AVStream *st, char **conf) -{ - int ret; - size_t newsize; - av_assert0(conf && st); - if (!*conf) - return 0; - if (!st->recommended_encoder_configuration) { - st->recommended_encoder_configuration = *conf; - *conf = 0; - return 0; - } - newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2; - if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0) - return ret; - av_strlcat(st->recommended_encoder_configuration, ",", newsize); - av_strlcat(st->recommended_encoder_configuration, *conf, newsize); - av_freep(conf); - return 0; -} - -#define VALIDATE_PARAMETER(parameter, name, check) { \ - if (check) { \ - av_log(s, AV_LOG_ERROR, "Invalid " name " %d\n", codecpar->parameter); \ - ret = AVERROR_INVALIDDATA; \ - goto fail; \ - } \ -} - -static int ffm2_read_header(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVStream *st = NULL; - AVIOContext *pb = s->pb; - AVCodecContext *dummy_codec = NULL; - AVCodecParameters *codecpar = NULL; - const AVCodecDescriptor *codec_desc; - int ret; - int f_main = 0, f_cprv = -1, f_stvi = -1, f_stau = -1; - AVCodec *enc; - char *buffer; - - ffm->packet_size = avio_rb32(pb); - if (ffm->packet_size != FFM_PACKET_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid packet size %d, expected size was %d\n", - ffm->packet_size, FFM_PACKET_SIZE); - ret = AVERROR_INVALIDDATA; - goto fail; - } - - ffm->write_index = avio_rb64(pb); - /* get also filesize */ - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { - ffm->file_size = avio_size(pb); - if (ffm->write_index && 0) - adjust_write_index(s); - } else { - ffm->file_size = (UINT64_C(1) << 63) - 1; - } - dummy_codec = avcodec_alloc_context3(NULL); - - while(!avio_feof(pb)) { - unsigned id = avio_rb32(pb); - unsigned size = avio_rb32(pb); - int64_t next = avio_tell(pb) + size; - char rc_eq_buf[128]; - int flags; - - if(!id) - break; - - switch(id) { - case MKBETAG('M', 'A', 'I', 'N'): - if (f_main++) { - ret = AVERROR(EINVAL); - goto fail; - } - avio_rb32(pb); /* nb_streams */ - avio_rb32(pb); /* total bitrate */ - break; - case MKBETAG('C', 'O', 'M', 'M'): - f_cprv = f_stvi = f_stau = 0; - st = avformat_new_stream(s, NULL); - if (!st) { - ret = AVERROR(ENOMEM); - goto fail; - } - - avpriv_set_pts_info(st, 64, 1, 1000000); - - codecpar = st->codecpar; - /* generic info */ - codecpar->codec_id = avio_rb32(pb); - codec_desc = avcodec_descriptor_get(codecpar->codec_id); - if (!codec_desc) { - av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id); - codecpar->codec_id = AV_CODEC_ID_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->codec_type = avio_r8(pb); - if (codecpar->codec_type != codec_desc->type) { - av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n", - codec_desc->type, codecpar->codec_type); - codecpar->codec_id = AV_CODEC_ID_NONE; - codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->bit_rate = avio_rb32(pb); - if (codecpar->bit_rate < 0) { - av_log(s, AV_LOG_ERROR, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate); - ret = AVERROR_INVALIDDATA; - goto fail; - } - flags = avio_rb32(pb); -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - st->codec->flags = flags; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - avio_rb32(pb); // flags2 - avio_rb32(pb); // debug - if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) { - int size = avio_rb32(pb); - if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size); - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!codecpar->extradata) { - ret = AVERROR(ENOMEM); - goto fail; - } - codecpar->extradata_size = size; - avio_read(pb, codecpar->extradata, size); - } - break; - case MKBETAG('S', 'T', 'V', 'I'): - if (f_stvi++ || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { - ret = AVERROR(EINVAL); - goto fail; - } - avio_rb32(pb); // time_base.num - avio_rb32(pb); // time_base.den - codecpar->width = avio_rb16(pb); - codecpar->height = avio_rb16(pb); - ret = av_image_check_size(codecpar->width, codecpar->height, 0, s); - if (ret < 0) - goto fail; - avio_rb16(pb); // gop_size - codecpar->format = avio_rb32(pb); - if (!av_pix_fmt_desc_get(codecpar->format)) { - av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format); - codecpar->format = AV_PIX_FMT_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - avio_r8(pb); // qmin - avio_r8(pb); // qmax - avio_r8(pb); // max_qdiff - avio_rb16(pb); // qcompress / 10000.0 - avio_rb16(pb); // qblur / 10000.0 - avio_rb32(pb); // bit_rate_tolerance - avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); - - avio_rb32(pb); // rc_max_rate - avio_rb32(pb); // rc_min_rate - avio_rb32(pb); // rc_buffer_size - avio_rb64(pb); // i_quant_factor - avio_rb64(pb); // b_quant_factor - avio_rb64(pb); // i_quant_offset - avio_rb64(pb); // b_quant_offset - avio_rb32(pb); // dct_algo - avio_rb32(pb); // strict_std_compliance - avio_rb32(pb); // max_b_frames - avio_rb32(pb); // mpeg_quant - avio_rb32(pb); // intra_dc_precision - avio_rb32(pb); // me_method - avio_rb32(pb); // mb_decision - avio_rb32(pb); // nsse_weight - avio_rb32(pb); // frame_skip_cmp - avio_rb64(pb); // rc_buffer_aggressivity - codecpar->codec_tag = avio_rb32(pb); - avio_r8(pb); // thread_count - avio_rb32(pb); // coder_type - avio_rb32(pb); // me_cmp - avio_rb32(pb); // me_subpel_quality - avio_rb32(pb); // me_range - avio_rb32(pb); // keyint_min - avio_rb32(pb); // scenechange_threshold - avio_rb32(pb); // b_frame_strategy - avio_rb64(pb); // qcompress - avio_rb64(pb); // qblur - avio_rb32(pb); // max_qdiff - avio_rb32(pb); // refs - break; - case MKBETAG('S', 'T', 'A', 'U'): - if (f_stau++ || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { - ret = AVERROR(EINVAL); - goto fail; - } - codecpar->sample_rate = avio_rb32(pb); - VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0) - codecpar->channels = avio_rl16(pb); - VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0) - codecpar->frame_size = avio_rl16(pb); - VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0) - break; - case MKBETAG('C', 'P', 'R', 'V'): - if (f_cprv++) { - ret = AVERROR(EINVAL); - goto fail; - } - enc = avcodec_find_encoder(codecpar->codec_id); - if (enc && enc->priv_data_size && enc->priv_class) { - buffer = av_malloc(size + 1); - if (!buffer) { - ret = AVERROR(ENOMEM); - goto fail; - } - avio_get_str(pb, size, buffer, size + 1); - if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) - goto fail; - } - break; - case MKBETAG('S', '2', 'V', 'I'): - if (f_stvi++ || !size || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { - ret = AVERROR(EINVAL); - goto fail; - } - buffer = av_malloc(size); - if (!buffer) { - ret = AVERROR(ENOMEM); - goto fail; - } - avio_get_str(pb, INT_MAX, buffer, size); - // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed - avcodec_parameters_to_context(dummy_codec, codecpar); - av_set_options_string(dummy_codec, buffer, "=", ","); - avcodec_parameters_from_context(codecpar, dummy_codec); - if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) - goto fail; - break; - case MKBETAG('S', '2', 'A', 'U'): - if (f_stau++ || !size || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { - ret = AVERROR(EINVAL); - goto fail; - } - buffer = av_malloc(size); - if (!buffer) { - ret = AVERROR(ENOMEM); - goto fail; - } - avio_get_str(pb, INT_MAX, buffer, size); - // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed - avcodec_parameters_to_context(dummy_codec, codecpar); - av_set_options_string(dummy_codec, buffer, "=", ","); - avcodec_parameters_from_context(codecpar, dummy_codec); - if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) - goto fail; - break; - } - avio_seek(pb, next, SEEK_SET); - } - - /* get until end of block reached */ - while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached) - avio_r8(pb); - - /* init packet demux */ - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet; - ffm->frame_offset = 0; - ffm->dts = 0; - ffm->read_state = READ_HEADER; - ffm->first_packet = 1; - avcodec_free_context(&dummy_codec); - return 0; - fail: - avcodec_free_context(&dummy_codec); - return ret; -} - -static int ffm_read_header(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVStream *st; - AVIOContext *pb = s->pb; - AVCodecContext *dummy_codec = NULL; - AVCodecParameters *codecpar; - const AVCodecDescriptor *codec_desc; - int i, nb_streams, ret; - uint32_t tag; - - /* header */ - tag = avio_rl32(pb); - if (tag == MKTAG('F', 'F', 'M', '2')) - return ffm2_read_header(s); - if (tag != MKTAG('F', 'F', 'M', '1')) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - ffm->packet_size = avio_rb32(pb); - if (ffm->packet_size != FFM_PACKET_SIZE) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - ffm->write_index = avio_rb64(pb); - /* get also filesize */ - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { - ffm->file_size = avio_size(pb); - if (ffm->write_index && 0) - adjust_write_index(s); - } else { - ffm->file_size = (UINT64_C(1) << 63) - 1; - } - dummy_codec = avcodec_alloc_context3(NULL); - - nb_streams = avio_rb32(pb); - avio_rb32(pb); /* total bitrate */ - /* read each stream */ - for(i=0;icodecpar; - /* generic info */ - codecpar->codec_id = avio_rb32(pb); - codec_desc = avcodec_descriptor_get(codecpar->codec_id); - if (!codec_desc) { - av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id); - codecpar->codec_id = AV_CODEC_ID_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->codec_type = avio_r8(pb); /* codec_type */ - if (codecpar->codec_type != codec_desc->type) { - av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n", - codec_desc->type, codecpar->codec_type); - codecpar->codec_id = AV_CODEC_ID_NONE; - codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->bit_rate = avio_rb32(pb); - if (codecpar->bit_rate < 0) { - av_log(s, AV_LOG_WARNING, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate); - ret = AVERROR_INVALIDDATA; - goto fail; - } - flags = avio_rb32(pb); -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - st->codec->flags = flags; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - avio_rb32(pb); // flags2 - avio_rb32(pb); // debug - /* specific info */ - switch(codecpar->codec_type) { - case AVMEDIA_TYPE_VIDEO: - avio_rb32(pb); // time_base.num - avio_rb32(pb); // time_base.den - codecpar->width = avio_rb16(pb); - codecpar->height = avio_rb16(pb); - if ((ret = av_image_check_size(codecpar->width, codecpar->height, 0, s)) < 0) - goto fail; - avio_rb16(pb); // gop_size - codecpar->format = avio_rb32(pb); - if (!av_pix_fmt_desc_get(codecpar->format)) { - av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format); - codecpar->format = AV_PIX_FMT_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - avio_r8(pb); // qmin - avio_r8(pb); // qmax - avio_r8(pb); // max_qdiff - avio_rb16(pb); // qcompress / 10000.0 - avio_rb16(pb); // qblur / 10000.0 - avio_rb32(pb); // bit_rate_tolerance - avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); - - avio_rb32(pb); // rc_max_rate - avio_rb32(pb); // rc_min_rate - avio_rb32(pb); // rc_buffer_size - avio_rb64(pb); // i_quant_factor - avio_rb64(pb); // b_quant_factor - avio_rb64(pb); // i_quant_offset - avio_rb64(pb); // b_quant_offset - avio_rb32(pb); // dct_algo - avio_rb32(pb); // strict_std_compliance - avio_rb32(pb); // max_b_frames - avio_rb32(pb); // mpeg_quant - avio_rb32(pb); // intra_dc_precision - avio_rb32(pb); // me_method - avio_rb32(pb); // mb_decision - avio_rb32(pb); // nsse_weight - avio_rb32(pb); // frame_skip_cmp - avio_rb64(pb); // rc_buffer_aggressivity - codecpar->codec_tag = avio_rb32(pb); - avio_r8(pb); // thread_count - avio_rb32(pb); // coder_type - avio_rb32(pb); // me_cmp - avio_rb32(pb); // me_subpel_quality - avio_rb32(pb); // me_range - avio_rb32(pb); // keyint_min - avio_rb32(pb); // scenechange_threshold - avio_rb32(pb); // b_frame_strategy - avio_rb64(pb); // qcompress - avio_rb64(pb); // qblur - avio_rb32(pb); // max_qdiff - avio_rb32(pb); // refs - break; - case AVMEDIA_TYPE_AUDIO: - codecpar->sample_rate = avio_rb32(pb); - VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0) - codecpar->channels = avio_rl16(pb); - VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0) - codecpar->frame_size = avio_rl16(pb); - VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0) - break; - default: - ret = AVERROR_INVALIDDATA; - goto fail; - } - if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) { - int size = avio_rb32(pb); - if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size); - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!codecpar->extradata) { - ret = AVERROR(ENOMEM); - goto fail; - } - codecpar->extradata_size = size; - avio_read(pb, codecpar->extradata, size); - } - } - - /* get until end of block reached */ - while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached) - avio_r8(pb); - - /* init packet demux */ - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet; - ffm->frame_offset = 0; - ffm->dts = 0; - ffm->read_state = READ_HEADER; - ffm->first_packet = 1; - avcodec_free_context(&dummy_codec); - return 0; - fail: - avcodec_free_context(&dummy_codec); - return ret; -} - -/* return < 0 if eof */ -static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - int size; - FFMContext *ffm = s->priv_data; - int duration, ret; - - switch(ffm->read_state) { - case READ_HEADER: - if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0) - return ret; - - ff_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n", - avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size); - if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != - FRAME_HEADER_SIZE) - return -1; - if (ffm->header[1] & FLAG_DTS) - if (ffm_read_data(s, ffm->header+16, 4, 1) != 4) - return -1; - ffm->read_state = READ_DATA; - /* fall through */ - case READ_DATA: - size = AV_RB24(ffm->header + 2); - if ((ret = ffm_is_avail_data(s, size)) < 0) - return ret; - - duration = AV_RB24(ffm->header + 5); - - if (av_new_packet(pkt, size) < 0) { - return AVERROR(ENOMEM); - } - pkt->stream_index = ffm->header[0]; - if ((unsigned)pkt->stream_index >= s->nb_streams) { - av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index); - av_packet_unref(pkt); - ffm->read_state = READ_HEADER; - return -1; - } - pkt->pos = avio_tell(s->pb); - if (ffm->header[1] & FLAG_KEY_FRAME) - pkt->flags |= AV_PKT_FLAG_KEY; - - ffm->read_state = READ_HEADER; - if (ffm_read_data(s, pkt->data, size, 0) != size) { - /* bad case: desynchronized packet. we cancel all the packet loading */ - av_packet_unref(pkt); - return -1; - } - pkt->pts = AV_RB64(ffm->header+8); - if (ffm->header[1] & FLAG_DTS) - pkt->dts = pkt->pts - AV_RB32(ffm->header+16); - else - pkt->dts = pkt->pts; - pkt->duration = duration; - break; - } - return 0; -} - -/* seek to a given time in the file. The file read pointer is - positioned at or before pts. XXX: the following code is quite - approximative */ -static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags) -{ - FFMContext *ffm = s->priv_data; - int64_t pos_min, pos_max, pos; - int64_t pts_min, pts_max, pts; - double pos1; - - ff_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); - /* find the position using linear interpolation (better than - dichotomy in typical cases) */ - if (ffm->write_index && ffm->write_index < ffm->file_size) { - if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) { - pos_min = FFM_PACKET_SIZE; - pos_max = ffm->write_index - FFM_PACKET_SIZE; - } else { - pos_min = ffm->write_index; - pos_max = ffm->file_size - FFM_PACKET_SIZE; - } - } else { - pos_min = FFM_PACKET_SIZE; - pos_max = ffm->file_size - FFM_PACKET_SIZE; - } - while (pos_min <= pos_max) { - pts_min = get_dts(s, pos_min); - pts_max = get_dts(s, pos_max); - if (pts_min > wanted_pts || pts_max <= wanted_pts) { - pos = pts_min > wanted_pts ? pos_min : pos_max; - goto found; - } - /* linear interpolation */ - pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / - (double)(pts_max - pts_min); - pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE; - if (pos <= pos_min) - pos = pos_min; - else if (pos >= pos_max) - pos = pos_max; - pts = get_dts(s, pos); - /* check if we are lucky */ - if (pts == wanted_pts) { - goto found; - } else if (pts > wanted_pts) { - pos_max = pos - FFM_PACKET_SIZE; - } else { - pos_min = pos + FFM_PACKET_SIZE; - } - } - pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; - - found: - if (ffm_seek1(s, pos) < 0) - return -1; - - /* reset read state */ - ffm->read_state = READ_HEADER; - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet; - ffm->first_packet = 1; - - return 0; -} - -static int ffm_probe(AVProbeData *p) -{ - if ( - p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && - (p->buf[3] == '1' || p->buf[3] == '2')) - return AVPROBE_SCORE_MAX + 1; - return 0; -} - -static const AVOption options[] = { - {"server_attached", NULL, offsetof(FFMContext, server_attached), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_EXPORT }, - {"ffm_write_index", NULL, offsetof(FFMContext, write_index), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_EXPORT }, - {"ffm_file_size", NULL, offsetof(FFMContext, file_size), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_EXPORT }, - { NULL }, -}; - -static const AVClass ffm_class = { - .class_name = "ffm demuxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; -AVInputFormat ff_ffm_demuxer = { - .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"), - .priv_data_size = sizeof(FFMContext), - .read_probe = ffm_probe, - .read_header = ffm_read_header, - .read_packet = ffm_read_packet, - .read_seek = ffm_seek, - .priv_class = &ffm_class, -}; diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c deleted file mode 100644 index ef7dc3a03..000000000 --- a/libavformat/ffmenc.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * FFM (ffserver live feed) muxer - * 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 - */ - -#include "libavutil/intreadwrite.h" -#include "libavutil/intfloat.h" -#include "libavutil/avassert.h" -#include "libavutil/parseutils.h" -#include "libavutil/opt.h" -#include "avformat.h" -#include "avio_internal.h" -#include "internal.h" -#include "ffm.h" - -static void flush_packet(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - int fill_size, h; - AVIOContext *pb = s->pb; - - fill_size = ffm->packet_end - ffm->packet_ptr; - memset(ffm->packet_ptr, 0, fill_size); - - av_assert1(avio_tell(pb) % ffm->packet_size == 0); - - /* put header */ - avio_wb16(pb, PACKET_ID); - avio_wb16(pb, fill_size); - avio_wb64(pb, ffm->dts); - h = ffm->frame_offset; - if (ffm->first_packet) - h |= 0x8000; - avio_wb16(pb, h); - avio_write(pb, ffm->packet, ffm->packet_end - ffm->packet); - avio_flush(pb); - - /* prepare next packet */ - ffm->frame_offset = 0; /* no key frame */ - ffm->packet_ptr = ffm->packet; - ffm->first_packet = 0; -} - -/* 'first' is true if first data of a frame */ -static void ffm_write_data(AVFormatContext *s, - const uint8_t *buf, int size, - int64_t dts, int header) -{ - FFMContext *ffm = s->priv_data; - int len; - - if (header && ffm->frame_offset == 0) { - ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE; - ffm->dts = dts; - } - - /* write as many packets as needed */ - while (size > 0) { - len = ffm->packet_end - ffm->packet_ptr; - if (len > size) - len = size; - memcpy(ffm->packet_ptr, buf, len); - - ffm->packet_ptr += len; - buf += len; - size -= len; - if (ffm->packet_ptr >= ffm->packet_end) - flush_packet(s); - } -} - -static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id) -{ - uint8_t *dyn_buf; - int dyn_size= avio_close_dyn_buf(dpb, &dyn_buf); - avio_wb32(pb, id); - avio_wb32(pb, dyn_size); - avio_write(pb, dyn_buf, dyn_size); - av_free(dyn_buf); -} - -static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecParameters *ctxpar, unsigned tag, int type) -{ - AVIOContext *tmp; - char *buf = NULL; - int ret, need_coma = 0; - AVCodecContext *ctx = NULL; - -#define SKIP_DEFAULTS AV_OPT_SERIALIZE_SKIP_DEFAULTS -#define OPT_FLAGS_EXACT AV_OPT_SERIALIZE_OPT_FLAGS_EXACT -#define ENC AV_OPT_FLAG_ENCODING_PARAM - - if (avio_open_dyn_buf(&tmp) < 0) - return AVERROR(ENOMEM); - - // AVCodecParameters does not suport AVOptions, we thus must copy it over to a context that does - // otherwise it could be used directly and this would be much simpler - ctx = avcodec_alloc_context3(NULL); - if (!ctx) { - ret = AVERROR(ENOMEM); - goto fail; - } - avcodec_parameters_to_context(ctx, ctxpar); - - if ((ret = av_opt_serialize(ctx, ENC | type, SKIP_DEFAULTS, &buf, '=', ',')) < 0) - goto fail; - if (buf && strlen(buf)) { - avio_write(tmp, buf, strlen(buf)); - av_freep(&buf); - need_coma = 1; - } - if ((ret = av_opt_serialize(ctx, 0, SKIP_DEFAULTS | OPT_FLAGS_EXACT, &buf, '=', ',')) < 0) - goto fail; - if (buf && strlen(buf)) { - if (need_coma) - avio_w8(tmp, ','); - avio_write(tmp, buf, strlen(buf)); - } - av_freep(&buf); - avio_w8(tmp, 0); - write_header_chunk(pb, tmp, tag); - avcodec_free_context(&ctx); - return 0; - fail: - av_free(buf); - ffio_free_dyn_buf(&tmp); - avcodec_free_context(&ctx); - return ret; - -#undef SKIP_DEFAULTS -#undef OPT_FLAGS_EXACT -#undef ENC -} - -static int ffm_write_recommended_config(AVIOContext *pb, AVCodecParameters *codecpar, unsigned tag, - const char *configuration) -{ - int ret; - const AVCodec *enc = avcodec_find_encoder(codecpar->codec_id); - AVIOContext *tmp; - AVDictionaryEntry *t = NULL; - AVDictionary *all = NULL, *comm = NULL, *prv = NULL; - char *buf = NULL; - - if (!enc || !enc->priv_class || !enc->priv_data_size) { - /* codec is not known/has no private options, so save everything as common options */ - if (avio_open_dyn_buf(&tmp) < 0) - return AVERROR(ENOMEM); - avio_put_str(tmp, configuration); - write_header_chunk(pb, tmp, tag); - return 0; - } - - if ((ret = av_dict_parse_string(&all, configuration, "=", ",", 0)) < 0) - return ret; - - while ((t = av_dict_get(all, "", t, AV_DICT_IGNORE_SUFFIX))) { - if (av_opt_find((void *)&enc->priv_class, t->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { - if ((ret = av_dict_set(&prv, t->key, t->value, 0)) < 0) - goto fail; - } else if ((ret = av_dict_set(&comm, t->key, t->value, 0)) < 0) - goto fail; - } - - if (comm) { - if ((ret = av_dict_get_string(comm, &buf, '=', ',')) < 0 || - (ret = avio_open_dyn_buf(&tmp)) < 0) - goto fail; - avio_put_str(tmp, buf); - av_freep(&buf); - write_header_chunk(pb, tmp, tag); - } - if (prv) { - if ((ret = av_dict_get_string(prv, &buf, '=', ',')) < 0 || - (ret = avio_open_dyn_buf(&tmp)) < 0) - goto fail; - avio_put_str(tmp, buf); - write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); - } - - fail: - av_free(buf); - av_dict_free(&all); - av_dict_free(&comm); - av_dict_free(&prv); - return ret; -} - -static int ffm_write_header(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVStream *st; - AVIOContext *pb = s->pb; - AVCodecParameters *codecpar; - int bit_rate, i, ret; - - if ((ret = ff_parse_creation_time_metadata(s, &ffm->start_time, 0)) < 0) - return ret; - - ffm->packet_size = FFM_PACKET_SIZE; - - /* header */ - avio_wl32(pb, MKTAG('F', 'F', 'M', '2')); - avio_wb32(pb, ffm->packet_size); - avio_wb64(pb, 0); /* current write position */ - - if(avio_open_dyn_buf(&pb) < 0) - return AVERROR(ENOMEM); - - avio_wb32(pb, s->nb_streams); - bit_rate = 0; - for(i=0;inb_streams;i++) { - st = s->streams[i]; - bit_rate += st->codecpar->bit_rate; - } - avio_wb32(pb, bit_rate); - - write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N')); - - /* list of streams */ - for(i=0;inb_streams;i++) { - int flags = 0; - st = s->streams[i]; - avpriv_set_pts_info(st, 64, 1, 1000000); - if(avio_open_dyn_buf(&pb) < 0) - return AVERROR(ENOMEM); - - codecpar = st->codecpar; - /* generic info */ - avio_wb32(pb, codecpar->codec_id); - avio_w8(pb, codecpar->codec_type); - avio_wb32(pb, codecpar->bit_rate); - if (codecpar->extradata_size) - flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - - // If the user is not providing us with a configuration we have to fill it in as we cannot access the encoder - if (!st->recommended_encoder_configuration) { - if (s->flags & AVFMT_FLAG_BITEXACT) - flags |= AV_CODEC_FLAG_BITEXACT; - } - - avio_wb32(pb, flags); - avio_wb32(pb, 0); // flags2 - avio_wb32(pb, 0); // debug - if (codecpar->extradata_size) { - avio_wb32(pb, codecpar->extradata_size); - avio_write(pb, codecpar->extradata, codecpar->extradata_size); - } - write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M')); - /* specific info */ - switch(codecpar->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (st->recommended_encoder_configuration) { - av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", - st->recommended_encoder_configuration); - if ((ret = ffm_write_recommended_config(s->pb, codecpar, MKBETAG('S', '2', 'V', 'I'), - st->recommended_encoder_configuration)) < 0) - return ret; - } else if ((ret = ffm_write_header_codec_ctx(s->pb, codecpar, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0) - return ret; - break; - case AVMEDIA_TYPE_AUDIO: - if (st->recommended_encoder_configuration) { - av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", - st->recommended_encoder_configuration); - if ((ret = ffm_write_recommended_config(s->pb, codecpar, MKBETAG('S', '2', 'A', 'U'), - st->recommended_encoder_configuration)) < 0) - return ret; - } else if ((ret = ffm_write_header_codec_ctx(s->pb, codecpar, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0) - return ret; - break; - default: - return -1; - } - } - pb = s->pb; - - avio_wb64(pb, 0); // end of header - - /* flush until end of block reached */ - while ((avio_tell(pb) % ffm->packet_size) != 0) - avio_w8(pb, 0); - - avio_flush(pb); - - /* init packet mux */ - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE; - av_assert0(ffm->packet_end >= ffm->packet); - ffm->frame_offset = 0; - ffm->dts = 0; - ffm->first_packet = 1; - - return 0; -} - -static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - FFMContext *ffm = s->priv_data; - int64_t dts; - uint8_t header[FRAME_HEADER_SIZE+4]; - int header_size = FRAME_HEADER_SIZE; - - dts = ffm->start_time + pkt->dts; - /* packet size & key_frame */ - header[0] = pkt->stream_index; - header[1] = 0; - if (pkt->flags & AV_PKT_FLAG_KEY) - header[1] |= FLAG_KEY_FRAME; - AV_WB24(header+2, pkt->size); - AV_WB24(header+5, pkt->duration); - AV_WB64(header+8, ffm->start_time + pkt->pts); - if (pkt->pts != pkt->dts) { - header[1] |= FLAG_DTS; - AV_WB32(header+16, pkt->pts - pkt->dts); - header_size += 4; - } - ffm_write_data(s, header, header_size, dts, 1); - ffm_write_data(s, pkt->data, pkt->size, dts, 0); - - return 0; -} - -static int ffm_write_trailer(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - - /* flush packets */ - if (ffm->packet_ptr > ffm->packet) - flush_packet(s); - - return 0; -} - -AVOutputFormat ff_ffm_muxer = { - .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"), - .extensions = "ffm", - .priv_data_size = sizeof(FFMContext), - .audio_codec = AV_CODEC_ID_MP2, - .video_codec = AV_CODEC_ID_MPEG1VIDEO, - .write_header = ffm_write_header, - .write_packet = ffm_write_packet, - .write_trailer = ffm_write_trailer, - .flags = AVFMT_TS_NEGATIVE, -}; diff --git a/libavformat/fitsenc.c b/libavformat/fitsenc.c index 7cb171596..cc3999aa8 100644 --- a/libavformat/fitsenc.c +++ b/libavformat/fitsenc.c @@ -106,6 +106,8 @@ static int write_image_header(AVFormatContext *s) } bzero = 32768; break; + default: + return AVERROR(EINVAL); } if (fitsctx->first_image) { @@ -166,7 +168,9 @@ static int write_image_header(AVFormatContext *s) static int fits_write_packet(AVFormatContext *s, AVPacket *pkt) { - write_image_header(s); + int ret = write_image_header(s); + if (ret < 0) + return ret; avio_write(s->pb, pkt->data, pkt->size); return 0; } diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 2d89bef15..0217cef84 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -1152,6 +1152,12 @@ retry_duration: st->codecpar->codec_id == AV_CODEC_ID_MPEG4) { int type = avio_r8(s->pb); size--; + + if (size < 0) { + ret = AVERROR_INVALIDDATA; + goto leave; + } + if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4) { // sign extension int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000; diff --git a/libavformat/format.c b/libavformat/format.c index 38ca2a346..759b5b1ab 100644 --- a/libavformat/format.c +++ b/libavformat/format.c @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/atomic.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "avio_internal.h" #include "avformat.h" @@ -58,28 +58,40 @@ AVOutputFormat *av_oformat_next(const AVOutputFormat *f) return first_oformat; } +static AVMutex iformat_register_mutex = AV_MUTEX_INITIALIZER; + void av_register_input_format(AVInputFormat *format) { - AVInputFormat **p = last_iformat; + AVInputFormat **p; - // Note, format could be added after the first 2 checks but that implies that *p is no longer NULL - while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) + ff_mutex_lock(&iformat_register_mutex); + p = last_iformat; + + while (*p) p = &(*p)->next; + *p = format; + format->next = NULL; + last_iformat = &format->next; - if (!format->next) - last_iformat = &format->next; + ff_mutex_unlock(&iformat_register_mutex); } +static AVMutex oformat_register_mutex = AV_MUTEX_INITIALIZER; + void av_register_output_format(AVOutputFormat *format) { - AVOutputFormat **p = last_oformat; + AVOutputFormat **p; - // Note, format could be added after the first 2 checks but that implies that *p is no longer NULL - while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) + ff_mutex_lock(&oformat_register_mutex); + p = last_oformat; + + while (*p) p = &(*p)->next; + *p = format; + format->next = NULL; + last_oformat = &format->next; - if (!format->next) - last_oformat = &format->next; + ff_mutex_unlock(&oformat_register_mutex); } int av_match_ext(const char *filename, const char *extensions) diff --git a/libavformat/hevc.c b/libavformat/hevc.c index 1a2d6cdd2..e45d2c08d 100644 --- a/libavformat/hevc.c +++ b/libavformat/hevc.c @@ -417,7 +417,7 @@ static void skip_scaling_list_data(GetBitContext *gb) static int parse_rps(GetBitContext *gb, unsigned int rps_idx, unsigned int num_rps, - unsigned int num_delta_pocs[HEVC_MAX_SHORT_TERM_RPS_COUNT]) + unsigned int num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]) { unsigned int i; @@ -486,7 +486,7 @@ static int hvcc_parse_sps(GetBitContext *gb, HEVCDecoderConfigurationRecord *hvcc) { unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4; - unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_RPS_COUNT]; + unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; skip_bits(gb, 4); // sps_video_parameter_set_id @@ -556,7 +556,7 @@ static int hvcc_parse_sps(GetBitContext *gb, } num_short_term_ref_pic_sets = get_ue_golomb_long(gb); - if (num_short_term_ref_pic_sets > HEVC_MAX_SHORT_TERM_RPS_COUNT) + if (num_short_term_ref_pic_sets > HEVC_MAX_SHORT_TERM_REF_PIC_SETS) return AVERROR_INVALIDDATA; for (i = 0; i < num_short_term_ref_pic_sets; i++) { diff --git a/libavformat/hls.c b/libavformat/hls.c index 786934af0..950cc4c3b 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -26,6 +26,7 @@ * http://tools.ietf.org/html/draft-pantos-http-live-streaming */ +#include "libavformat/http.h" #include "libavutil/avstring.h" #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" @@ -94,6 +95,9 @@ struct playlist { AVIOContext pb; uint8_t* read_buffer; AVIOContext *input; + int input_read_done; + AVIOContext *input_next; + int input_next_requested; AVFormatContext *parent; int index; AVFormatContext *ctx; @@ -111,7 +115,7 @@ struct playlist { int start_seq_no; int n_segments; struct segment **segments; - int needed, cur_needed; + int needed; int cur_seq_no; int64_t cur_seg_offset; int64_t last_load_time; @@ -206,6 +210,9 @@ typedef struct HLSContext { int strict_std_compliance; char *allowed_extensions; int max_reload; + int http_persistent; + int http_multiple; + AVIOContext *playlist_pb; } HLSContext; static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) @@ -256,6 +263,10 @@ static void free_playlist_list(HLSContext *c) av_freep(&pls->pb.buffer); if (pls->input) ff_format_io_close(c->ctx, &pls->input); + pls->input_read_done = 0; + if (pls->input_next) + ff_format_io_close(c->ctx, &pls->input_next); + pls->input_next_requested = 0; if (pls->ctx) { pls->ctx->pb = NULL; avformat_close_input(&pls->ctx); @@ -597,13 +608,32 @@ static void update_options(char **dest, const char *name, void *src) av_freep(dest); } +static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb, + const char *url) +{ +#if !CONFIG_HTTP_PROTOCOL + return AVERROR_PROTOCOL_NOT_FOUND; +#else + int ret; + URLContext *uc = ffio_geturlcontext(*pb); + av_assert0(uc); + (*pb)->eof_reached = 0; + ret = ff_http_do_new_request(uc, url); + if (ret < 0) { + ff_format_io_close(s, pb); + } + return ret; +#endif +} + static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, - AVDictionary *opts, AVDictionary *opts2, int *is_http) + AVDictionary *opts, AVDictionary *opts2, int *is_http_out) { HLSContext *c = s->priv_data; AVDictionary *tmp = NULL; const char *proto_name = NULL; int ret; + int is_http = 0; av_dict_copy(&tmp, opts, 0); av_dict_copy(&tmp, opts2, 0); @@ -629,7 +659,7 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, return AVERROR_INVALIDDATA; } } else if (av_strstart(proto_name, "http", NULL)) { - ; + is_http = 1; } else return AVERROR_INVALIDDATA; @@ -640,7 +670,20 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5)) return AVERROR_INVALIDDATA; - ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + if (is_http && c->http_persistent && *pb) { + ret = open_url_keepalive(c->ctx, pb, url); + if (ret == AVERROR_EXIT) { + return ret; + } else if (ret < 0) { + if (ret != AVERROR_EOF) + av_log(s, AV_LOG_WARNING, + "keepalive request failed for '%s', retrying with new connection: %s\n", + url, av_err2str(ret)); + ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + } + } else { + ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + } if (ret >= 0) { // update cookies on http response with setcookies. char *new_cookies = NULL; @@ -658,8 +701,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, av_dict_free(&tmp); - if (is_http) - *is_http = av_strstart(proto_name, "http", NULL); + if (is_http_out) + *is_http_out = is_http; return ret; } @@ -682,11 +725,25 @@ static int parse_playlist(HLSContext *c, const char *url, struct variant_info variant_info; char tmp_str[MAX_URL_SIZE]; struct segment *cur_init_section = NULL; + int is_http = av_strstart(url, "http", NULL); + + if (is_http && !in && c->http_persistent && c->playlist_pb) { + in = c->playlist_pb; + ret = open_url_keepalive(c->ctx, &c->playlist_pb, url); + if (ret == AVERROR_EXIT) { + return ret; + } else if (ret < 0) { + if (ret != AVERROR_EOF) + av_log(c->ctx, AV_LOG_WARNING, + "keepalive request failed for '%s', retrying with new connection: %s\n", + url, av_err2str(ret)); + in = NULL; + } + } if (!in) { #if 1 AVDictionary *opts = NULL; - close_in = 1; /* Some HLS servers don't like being sent the range header */ av_dict_set(&opts, "seekable", "0", 0); @@ -696,10 +753,18 @@ static int parse_playlist(HLSContext *c, const char *url, av_dict_set(&opts, "headers", c->headers, 0); av_dict_set(&opts, "http_proxy", c->http_proxy, 0); + if (c->http_persistent) + av_dict_set(&opts, "multiple_requests", "1", 0); + ret = c->ctx->io_open(c->ctx, &in, url, AVIO_FLAG_READ, &opts); av_dict_free(&opts); if (ret < 0) return ret; + + if (is_http && c->http_persistent) + c->playlist_pb = in; + else + close_in = 1; #else ret = open_in(c, &in, url); if (ret < 0) @@ -873,6 +938,14 @@ static struct segment *current_segment(struct playlist *pls) return pls->segments[pls->cur_seq_no - pls->start_seq_no]; } +static struct segment *next_segment(struct playlist *pls) +{ + int n = pls->cur_seq_no - pls->start_seq_no + 1; + if (n >= pls->n_segments) + return NULL; + return pls->segments[n]; +} + enum ReadFromURLMode { READ_NORMAL, READ_COMPLETE, @@ -1098,7 +1171,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf, pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE); } -static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) +static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, AVIOContext **in) { AVDictionary *opts = NULL; int ret; @@ -1111,6 +1184,9 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) av_dict_set(&opts, "http_proxy", c->http_proxy, 0); av_dict_set(&opts, "seekable", "0", 0); + if (c->http_persistent) + av_dict_set(&opts, "multiple_requests", "1", 0); + if (seg->size >= 0) { /* try to restrict the HTTP request to the part we want * (if this is in fact a HTTP request) */ @@ -1122,12 +1198,12 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) seg->url, seg->url_offset, pls->index); if (seg->key_type == KEY_NONE) { - ret = open_url(pls->parent, &pls->input, seg->url, c->avio_opts, opts, &is_http); + ret = open_url(pls->parent, in, seg->url, c->avio_opts, opts, &is_http); } else if (seg->key_type == KEY_AES_128) { AVDictionary *opts2 = NULL; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { - AVIOContext *pb; + AVIOContext *pb = NULL; if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts, NULL) == 0) { ret = avio_read(pb, pls->key, sizeof(pls->key)); if (ret != sizeof(pls->key)) { @@ -1153,7 +1229,7 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) av_dict_set(&opts2, "key", key, 0); av_dict_set(&opts2, "iv", iv, 0); - ret = open_url(pls->parent, &pls->input, url, opts2, opts, &is_http); + ret = open_url(pls->parent, in, url, opts2, opts, &is_http); av_dict_free(&opts2); @@ -1180,11 +1256,11 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) * noticed without the call, though. */ if (ret == 0 && !is_http && seg->key_type == KEY_NONE && seg->url_offset) { - int64_t seekret = avio_seek(pls->input, seg->url_offset, SEEK_SET); + int64_t seekret = avio_seek(*in, seg->url_offset, SEEK_SET); if (seekret < 0) { av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url); ret = seekret; - ff_format_io_close(pls->parent, &pls->input); + ff_format_io_close(pls->parent, in); } } @@ -1210,7 +1286,7 @@ static int update_init_section(struct playlist *pls, struct segment *seg) if (!seg->init_section) return 0; - ret = open_input(c, pls, seg->init_section); + ret = open_input(c, pls, seg->init_section, &pls->input); if (ret < 0) { av_log(pls->parent, AV_LOG_WARNING, "Failed to open an initialization section in playlist %d\n", @@ -1258,33 +1334,72 @@ static int64_t default_reload_interval(struct playlist *pls) pls->target_duration; } +static int playlist_needed(struct playlist *pls) +{ + AVFormatContext *s = pls->parent; + int i, j; + int stream_needed = 0; + int first_st; + + /* If there is no context or streams yet, the playlist is needed */ + if (!pls->ctx || !pls->n_main_streams) + return 1; + + /* check if any of the streams in the playlist are needed */ + for (i = 0; i < pls->n_main_streams; i++) { + if (pls->main_streams[i]->discard < AVDISCARD_ALL) { + stream_needed = 1; + break; + } + } + + /* If all streams in the playlist were discarded, the playlist is not + * needed (regardless of whether whole programs are discarded or not). */ + if (!stream_needed) + return 0; + + /* Otherwise, check if all the programs (variants) this playlist is in are + * discarded. Since all streams in the playlist are part of the same programs + * we can just check the programs of the first stream. */ + + first_st = pls->main_streams[0]->index; + + for (i = 0; i < s->nb_programs; i++) { + AVProgram *program = s->programs[i]; + if (program->discard < AVDISCARD_ALL) { + for (j = 0; j < program->nb_stream_indexes; j++) { + if (program->stream_index[j] == first_st) { + /* playlist is in an undiscarded program */ + return 1; + } + } + } + } + + /* some streams were not discarded but all the programs were */ + return 0; +} + static int read_data(void *opaque, uint8_t *buf, int buf_size) { struct playlist *v = opaque; HLSContext *c = v->parent->priv_data; - int ret, i; + int ret; int just_opened = 0; int reload_count = 0; + struct segment *seg; restart: if (!v->needed) return AVERROR_EOF; - if (!v->input) { + if (!v->input || (c->http_persistent && v->input_read_done)) { int64_t reload_interval; - struct segment *seg; /* Check that the playlist is still needed before opening a new * segment. */ - if (v->ctx && v->ctx->nb_streams) { - v->needed = 0; - for (i = 0; i < v->n_main_streams; i++) { - if (v->main_streams[i]->discard < AVDISCARD_ALL) { - v->needed = 1; - break; - } - } - } + v->needed = playlist_needed(v); + if (!v->needed) { av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n", v->index); @@ -1329,6 +1444,7 @@ reload: goto reload; } + v->input_read_done = 0; seg = current_segment(v); /* load/update Media Initialization Section, if any */ @@ -1336,11 +1452,18 @@ reload: if (ret) return ret; - ret = open_input(c, v, seg); + if (c->http_multiple == 1 && v->input_next_requested) { + FFSWAP(AVIOContext *, v->input, v->input_next); + v->input_next_requested = 0; + ret = 0; + } else { + ret = open_input(c, v, seg, &v->input); + } if (ret < 0) { if (ff_check_interrupt(c->interrupt_callback)) return AVERROR_EXIT; - av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n", + av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %d of playlist %d\n", + v->cur_seq_no, v->index); v->cur_seq_no += 1; goto reload; @@ -1348,6 +1471,30 @@ reload: just_opened = 1; } + if (c->http_multiple == -1) { + uint8_t *http_version_opt = NULL; + int r = av_opt_get(v->input, "http_version", AV_OPT_SEARCH_CHILDREN, &http_version_opt); + if (r >= 0) { + c->http_multiple = strncmp((const char *)http_version_opt, "1.1", 3) == 0; + av_freep(&http_version_opt); + } + } + + seg = next_segment(v); + if (c->http_multiple == 1 && !v->input_next_requested && + seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + ret = open_input(c, v, seg, &v->input_next); + if (ret < 0) { + if (ff_check_interrupt(c->interrupt_callback)) + return AVERROR_EXIT; + av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %d of playlist %d\n", + v->cur_seq_no + 1, + v->index); + } else { + v->input_next_requested = 1; + } + } + if (v->init_sec_buf_read_offset < v->init_sec_data_len) { /* Push init section out first before first actual segment */ int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size); @@ -1356,7 +1503,8 @@ reload: return copy_size; } - ret = read_from_url(v, current_segment(v), buf, buf_size, READ_NORMAL); + seg = current_segment(v); + ret = read_from_url(v, seg, buf, buf_size, READ_NORMAL); if (ret > 0) { if (just_opened && v->is_id3_timestamped != 0) { /* Intercept ID3 tags here, elementary audio streams are required @@ -1366,7 +1514,12 @@ reload: return ret; } - ff_format_io_close(v->parent, &v->input); + if (c->http_persistent && + seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + v->input_read_done = 1; + } else { + ff_format_io_close(v->parent, &v->input); + } v->cur_seq_no++; c->cur_seq_no = v->cur_seq_no; @@ -1627,6 +1780,7 @@ static int hls_close(AVFormatContext *s) free_rendition_list(c); av_dict_free(&c->avio_opts); + ff_format_io_close(c->ctx, &c->playlist_pb); return 0; } @@ -1841,20 +1995,15 @@ static int recheck_discard_flags(AVFormatContext *s, int first) { HLSContext *c = s->priv_data; int i, changed = 0; + int cur_needed; /* Check if any new streams are needed */ - for (i = 0; i < c->n_playlists; i++) - c->playlists[i]->cur_needed = 0; - - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - struct playlist *pls = c->playlists[s->streams[i]->id]; - if (st->discard < AVDISCARD_ALL) - pls->cur_needed = 1; - } for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; - if (pls->cur_needed && !pls->needed) { + + cur_needed = playlist_needed(c->playlists[i]); + + if (cur_needed && !pls->needed) { pls->needed = 1; changed = 1; pls->cur_seq_no = select_cur_seq_no(c, pls); @@ -1866,9 +2015,13 @@ static int recheck_discard_flags(AVFormatContext *s, int first) pls->seek_stream_index = -1; } av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %d\n", i, pls->cur_seq_no); - } else if (first && !pls->cur_needed && pls->needed) { + } else if (first && !cur_needed && pls->needed) { if (pls->input) ff_format_io_close(pls->parent, &pls->input); + pls->input_read_done = 0; + if (pls->input_next) + ff_format_io_close(pls->parent, &pls->input_next); + pls->input_next_requested = 0; pls->needed = 0; changed = 1; av_log(s, AV_LOG_INFO, "No longer receiving playlist %d\n", i); @@ -2103,6 +2256,10 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, struct playlist *pls = c->playlists[i]; if (pls->input) ff_format_io_close(pls->parent, &pls->input); + pls->input_read_done = 0; + if (pls->input_next) + ff_format_io_close(pls->parent, &pls->input_next); + pls->input_next_requested = 0; av_packet_unref(&pls->pkt); reset_packet(&pls->pkt); pls->pb.eof_reached = 0; @@ -2157,6 +2314,10 @@ static const AVOption hls_options[] = { INT_MIN, INT_MAX, FLAGS}, {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded", OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS}, + {"http_persistent", "Use persistent HTTP connections", + OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, + {"http_multiple", "Use multiple HTTP connections for fetching segments", + OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS}, {NULL} }; diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 418f153c6..e36120c32 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1,6 +1,7 @@ /* * Apple HTTP Live Streaming segmenter * Copyright (c) 2012, Luca Barbato + * Copyright (c) 2017 Akamai Technologies, Inc. * * This file is part of FFmpeg. * @@ -44,6 +45,10 @@ #include "avformat.h" #include "avio_internal.h" +#if CONFIG_HTTP_PROTOCOL +#include "http.h" +#endif +#include "hlsplaylist.h" #include "internal.h" #include "os_support.h" @@ -56,6 +61,7 @@ typedef enum { #define KEYSIZE 16 #define LINE_BUFFER_SIZE 1024 #define HLS_MICROSECOND_UNIT 1000000 +#define POSTFIX_PATTERN "_%d" typedef struct HLSSegment { char filename[1024]; @@ -86,6 +92,7 @@ typedef enum HLSFlags { HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s HLS_TEMP_FILE = (1 << 11), HLS_PERIODIC_REKEY = (1 << 12), + HLS_INDEPENDENT_SEGMENTS = (1 << 13), } HLSFlags; typedef enum { @@ -93,25 +100,59 @@ typedef enum { SEGMENT_TYPE_FMP4, } SegmentType; -typedef enum { - PLAYLIST_TYPE_NONE, - PLAYLIST_TYPE_EVENT, - PLAYLIST_TYPE_VOD, - PLAYLIST_TYPE_NB, -} PlaylistType; - -typedef struct HLSContext { - const AVClass *class; // Class for private options. +typedef struct VariantStream { unsigned number; int64_t sequence; - int64_t start_sequence; - uint32_t start_sequence_source_type; // enum StartSequenceSourceType AVOutputFormat *oformat; AVOutputFormat *vtt_oformat; + AVIOContext *out; + int packets_written; + int init_range_length; AVFormatContext *avf; AVFormatContext *vtt_avf; + int has_video; + int has_subtitle; + int new_start; + double dpp; // duration per packet + int64_t start_pts; + int64_t end_pts; + double duration; // last segment duration computed so far, in seconds + int64_t start_pos; // last segment starting position + int64_t size; // last segment size + int nb_entries; + int discontinuity_set; + int discontinuity; + + HLSSegment *segments; + HLSSegment *last_segment; + HLSSegment *old_segments; + + char *basename; + char *vtt_basename; + char *vtt_m3u8_name; + char *m3u8_name; + + double initial_prog_date_time; + char current_segment_final_filename_fmt[1024]; // when renaming segments + + char *fmp4_init_filename; + char *base_output_dirname; + int fmp4_init_mode; + + AVStream **streams; + unsigned int nb_streams; + int m3u8_created; /* status of media play-list creation */ + char *agroup; /* audio group name */ + char *baseurl; +} VariantStream; + +typedef struct HLSContext { + const AVClass *class; // Class for private options. + int64_t start_sequence; + uint32_t start_sequence_source_type; // enum StartSequenceSourceType + float time; // Set by a private option. float init_time; // Set by a private option. int max_nb_segments; // Set by a private option. @@ -123,34 +164,13 @@ typedef struct HLSContext { char *segment_filename; char *fmp4_init_filename; int segment_type; - int fmp4_init_mode; int use_localtime; ///< flag to expand filename with localtime int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename int allowcache; int64_t recording_time; - int has_video; - int has_subtitle; - int new_start; - double dpp; // duration per packet - int64_t start_pts; - int64_t end_pts; - double duration; // last segment duration computed so far, in seconds - int64_t start_pos; // last segment starting position - int64_t size; // last segment size int64_t max_seg_size; // every segment file max size - int nb_entries; - int discontinuity_set; - int discontinuity; - HLSSegment *segments; - HLSSegment *last_segment; - HLSSegment *old_segments; - - char *basename; - char *base_output_dirname; - char *vtt_basename; - char *vtt_m3u8_name; char *baseurl; char *format_options_str; char *vtt_format_options_str; @@ -162,6 +182,7 @@ typedef struct HLSContext { char *key_url; char *iv; char *key_basename; + int encrypt_started; char *key_info_file; char key_file[LINE_BUFFER_SIZE + 1]; @@ -171,16 +192,21 @@ typedef struct HLSContext { AVDictionary *vtt_format_options; char *method; - - double initial_prog_date_time; - char current_segment_final_filename_fmt[1024]; // when renaming segments char *user_agent; -} HLSContext; -static int get_int_from_double(double val) -{ - return (int)((val - (int)val) >= 0.001) ? (int)(val + 1) : (int)val; -} + VariantStream *var_streams; + unsigned int nb_varstreams; + + int master_m3u8_created; /* status of master play-list creation */ + char *master_m3u8_url; /* URL of the master m3u8 file */ + int version; /* HLS version */ + char *var_stream_map; /* user specified variant stream map string */ + char *master_pl_name; + unsigned int master_publish_rate; + int http_persistent; + AVIOContext *m3u8_out; + AVIOContext *sub_m3u8_out; +} HLSContext; static int mkdir_p(const char *path) { int ret = 0; @@ -215,10 +241,41 @@ static int mkdir_p(const char *path) { return ret; } +static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, + AVDictionary **options) { + HLSContext *hls = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + int err = AVERROR_MUXER_NOT_FOUND; + if (!*pb || !http_base_proto || !hls->http_persistent) { + err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + err = ff_http_do_new_request(http_url_context, filename); +#endif + } + return err; +} + +static void hlsenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) { + HLSContext *hls = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + if (!http_base_proto || !hls->http_persistent || hls->key_info_file || hls->encrypt) { + ff_format_io_close(s, pb); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + avio_flush(*pb); + ffurl_shutdown(http_url_context, AVIO_FLAG_WRITE); +#endif + } +} + static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSContext *c) { - const char *proto = avio_find_protocol_name(s->filename); - int http_base_proto = proto ? (!av_strcasecmp(proto, "http") || !av_strcasecmp(proto, "https")) : 0; + int http_base_proto = ff_is_http_proto(s->filename); if (c->method) { av_dict_set(options, "method", c->method, 0); @@ -228,6 +285,8 @@ static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSCont } if (c->user_agent) av_dict_set(options, "user_agent", c->user_agent, 0); + if (c->http_persistent) + av_dict_set_int(options, "multiple_requests", 1, 0); } @@ -293,7 +352,31 @@ static void write_styp(AVIOContext *pb) ffio_wfourcc(pb, "msix"); } -static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { +static int flush_dynbuf(VariantStream *vs, int *range_length) +{ + AVFormatContext *ctx = vs->avf; + uint8_t *buffer; + + if (!ctx->pb) { + return AVERROR(EINVAL); + } + + // flush + av_write_frame(ctx, NULL); + avio_flush(ctx->pb); + + // write out to file + *range_length = avio_close_dyn_buf(ctx->pb, &buffer); + ctx->pb = NULL; + avio_write(vs->out, buffer, *range_length); + av_free(buffer); + + // re-open buffer + return avio_open_dyn_buf(&ctx->pb); +} + +static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, + VariantStream *vs) { HLSSegment *segment, *previous_segment = NULL; float playlist_duration = 0.0f; @@ -304,13 +387,13 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { AVIOContext *out = NULL; const char *proto = NULL; - segment = hls->segments; + segment = vs->segments; while (segment) { playlist_duration += segment->duration; segment = segment->next; } - segment = hls->old_segments; + segment = vs->old_segments; while (segment) { playlist_duration -= segment->duration; previous_segment = segment; @@ -325,7 +408,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { if (hls->segment_filename) { dirname = av_strdup(hls->segment_filename); } else { - dirname = av_strdup(hls->avf->filename); + dirname = av_strdup(vs->avf->filename); } if (!dirname) { ret = AVERROR(ENOMEM); @@ -355,9 +438,9 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { proto = avio_find_protocol_name(s->filename); if (hls->method || (proto && !av_strcasecmp(proto, "http"))) { av_dict_set(&options, "method", "DELETE", 0); - if ((ret = hls->avf->io_open(hls->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) + if ((ret = vs->avf->io_open(vs->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) goto fail; - ff_format_io_close(hls->avf, &out); + ff_format_io_close(vs->avf, &out); } else if (unlink(path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", path, strerror(errno)); @@ -376,11 +459,11 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { if (hls->method || (proto && !av_strcasecmp(proto, "http"))) { av_dict_set(&options, "method", "DELETE", 0); - if ((ret = hls->avf->io_open(hls->avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { + if ((ret = vs->avf->io_open(vs->avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { av_free(sub_path); goto fail; } - ff_format_io_close(hls->avf, &out); + ff_format_io_close(vs->avf, &out); } else if (unlink(sub_path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", sub_path, strerror(errno)); @@ -414,7 +497,7 @@ static int randomize(uint8_t *buf, int len) return AVERROR(EINVAL); } -static int do_encrypt(AVFormatContext *s) +static int do_encrypt(AVFormatContext *s, VariantStream *vs) { HLSContext *hls = s->priv_data; int ret; @@ -422,7 +505,7 @@ static int do_encrypt(AVFormatContext *s) AVIOContext *pb; uint8_t key[KEYSIZE]; - len = strlen(hls->basename) + 4 + 1; + len = strlen(s->filename) + 4 + 1; hls->key_basename = av_mallocz(len); if (!hls->key_basename) return AVERROR(ENOMEM); @@ -443,7 +526,7 @@ static int do_encrypt(AVFormatContext *s) char buf[33]; if (!hls->iv) { - AV_WB64(iv + 8, hls->sequence); + AV_WB64(iv + 8, vs->sequence); } else { memcpy(iv, hls->iv, sizeof(iv)); } @@ -543,7 +626,7 @@ static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) return len; } -static int hls_mux_init(AVFormatContext *s) +static int hls_mux_init(AVFormatContext *s, VariantStream *vs) { AVDictionary *options = NULL; HLSContext *hls = s->priv_data; @@ -552,13 +635,13 @@ static int hls_mux_init(AVFormatContext *s) int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); int i, ret; - ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL); + ret = avformat_alloc_output_context2(&vs->avf, vs->oformat, NULL, NULL); if (ret < 0) return ret; - oc = hls->avf; + oc = vs->avf; oc->filename[0] = '\0'; - oc->oformat = hls->oformat; + oc->oformat = vs->oformat; oc->interrupt_callback = s->interrupt_callback; oc->max_delay = s->max_delay; oc->opaque = s->opaque; @@ -566,51 +649,61 @@ static int hls_mux_init(AVFormatContext *s) oc->io_close = s->io_close; av_dict_copy(&oc->metadata, s->metadata, 0); - if(hls->vtt_oformat) { - ret = avformat_alloc_output_context2(&hls->vtt_avf, hls->vtt_oformat, NULL, NULL); + if(vs->vtt_oformat) { + ret = avformat_alloc_output_context2(&vs->vtt_avf, vs->vtt_oformat, NULL, NULL); if (ret < 0) return ret; - vtt_oc = hls->vtt_avf; - vtt_oc->oformat = hls->vtt_oformat; + vtt_oc = vs->vtt_avf; + vtt_oc->oformat = vs->vtt_oformat; av_dict_copy(&vtt_oc->metadata, s->metadata, 0); } - for (i = 0; i < s->nb_streams; i++) { + for (i = 0; i < vs->nb_streams; i++) { AVStream *st; AVFormatContext *loc; - if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + if (vs->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) loc = vtt_oc; else loc = oc; if (!(st = avformat_new_stream(loc, NULL))) return AVERROR(ENOMEM); - avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); + avcodec_parameters_copy(st->codecpar, vs->streams[i]->codecpar); if (!oc->oformat->codec_tag || - av_codec_get_id (oc->oformat->codec_tag, s->streams[i]->codecpar->codec_tag) == st->codecpar->codec_id || - av_codec_get_tag(oc->oformat->codec_tag, s->streams[i]->codecpar->codec_id) <= 0) { - st->codecpar->codec_tag = s->streams[i]->codecpar->codec_tag; + av_codec_get_id (oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_tag) == st->codecpar->codec_id || + av_codec_get_tag(oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_id) <= 0) { + st->codecpar->codec_tag = vs->streams[i]->codecpar->codec_tag; } else { st->codecpar->codec_tag = 0; } - st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; - st->time_base = s->streams[i]->time_base; - av_dict_copy(&st->metadata, s->streams[i]->metadata, 0); + st->sample_aspect_ratio = vs->streams[i]->sample_aspect_ratio; + st->time_base = vs->streams[i]->time_base; + av_dict_copy(&st->metadata, vs->streams[i]->metadata, 0); } - hls->start_pos = 0; - hls->new_start = 1; - hls->fmp4_init_mode = 0; + + vs->packets_written = 1; + vs->start_pos = 0; + vs->new_start = 1; + vs->fmp4_init_mode = 0; if (hls->segment_type == SEGMENT_TYPE_FMP4) { if (hls->max_seg_size > 0) { av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n"); return AVERROR_PATCHWELCOME; } - hls->fmp4_init_mode = !byterange_mode; + + vs->packets_written = 0; + vs->init_range_length = 0; + vs->fmp4_init_mode = !byterange_mode; set_http_options(s, &options, hls); - if ((ret = s->io_open(s, &oc->pb, hls->base_output_dirname, AVIO_FLAG_WRITE, &options)) < 0) { - av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", hls->fmp4_init_filename); + if ((ret = avio_open_dyn_buf(&oc->pb)) < 0) + return ret; + + ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options); + av_dict_free(&options); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename); return ret; } @@ -634,6 +727,7 @@ static int hls_mux_init(AVFormatContext *s) av_dict_free(&options); return AVERROR(EINVAL); } + avio_flush(oc->pb); av_dict_free(&options); } return 0; @@ -649,19 +743,20 @@ static HLSSegment *find_segment_by_filename(HLSSegment *segment, const char *fil return (HLSSegment *) NULL; } -static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls, HLSSegment *en, double duration, - int64_t pos, int64_t size) +static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls, + VariantStream *vs, HLSSegment *en, + double duration, int64_t pos, int64_t size) { if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && - strlen(hls->current_segment_final_filename_fmt)) { - av_strlcpy(hls->avf->filename, hls->current_segment_final_filename_fmt, sizeof(hls->avf->filename)); + strlen(vs->current_segment_final_filename_fmt)) { + av_strlcpy(vs->avf->filename, vs->current_segment_final_filename_fmt, sizeof(vs->avf->filename)); if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { - char * filename = av_strdup(hls->avf->filename); // %%s will be %s after strftime + char * filename = av_strdup(vs->avf->filename); // %%s will be %s after strftime if (!filename) { av_free(en); return AVERROR(ENOMEM); } - if (replace_int_data_in_filename(hls->avf->filename, sizeof(hls->avf->filename), + if (replace_int_data_in_filename(vs->avf->filename, sizeof(vs->avf->filename), filename, 's', pos + size) < 1) { av_log(hls, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " @@ -674,12 +769,12 @@ static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls av_free(filename); } if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { - char * filename = av_strdup(hls->avf->filename); // %%t will be %t after strftime + char * filename = av_strdup(vs->avf->filename); // %%t will be %t after strftime if (!filename) { av_free(en); return AVERROR(ENOMEM); } - if (replace_int_data_in_filename(hls->avf->filename, sizeof(hls->avf->filename), + if (replace_int_data_in_filename(vs->avf->filename, sizeof(vs->avf->filename), filename, 't', (int64_t)round(duration * HLS_MICROSECOND_UNIT)) < 1) { av_log(hls, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " @@ -718,9 +813,9 @@ static int sls_flag_check_duration_size_index(HLSContext *hls) return ret; } -static int sls_flag_check_duration_size(HLSContext *hls) +static int sls_flag_check_duration_size(HLSContext *hls, VariantStream *vs) { - const char *proto = avio_find_protocol_name(hls->basename); + const char *proto = avio_find_protocol_name(vs->basename); int segment_renaming_ok = proto && !strcmp(proto, "file"); int ret = 0; @@ -738,14 +833,14 @@ static int sls_flag_check_duration_size(HLSContext *hls) return ret; } -static void sls_flag_file_rename(HLSContext *hls, char *old_filename) { +static void sls_flag_file_rename(HLSContext *hls, VariantStream *vs, char *old_filename) { if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && - strlen(hls->current_segment_final_filename_fmt)) { - ff_rename(old_filename, hls->avf->filename, hls); + strlen(vs->current_segment_final_filename_fmt)) { + ff_rename(old_filename, vs->avf->filename, hls); } } -static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c) +static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c, VariantStream *vs) { if (c->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) { char * filename = av_strdup(oc->filename); // %%d will be %d after strftime @@ -753,9 +848,9 @@ static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c) return AVERROR(ENOMEM); if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), #if FF_API_HLS_WRAP - filename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + filename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - filename, 'd', c->sequence) < 1) { + filename, 'd', vs->sequence) < 1) { #endif av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " "you can try to remove second_level_segment_index flag\n", @@ -766,8 +861,8 @@ static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c) av_free(filename); } if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) { - av_strlcpy(c->current_segment_final_filename_fmt, oc->filename, - sizeof(c->current_segment_final_filename_fmt)); + av_strlcpy(vs->current_segment_final_filename_fmt, oc->filename, + sizeof(vs->current_segment_final_filename_fmt)); if (c->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { char * filename = av_strdup(oc->filename); // %%s will be %s after strftime if (!filename) @@ -799,8 +894,9 @@ static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c) } /* Create a new segment and append it to the segment list */ -static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double duration, - int64_t pos, int64_t size) +static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, + VariantStream *vs, double duration, int64_t pos, + int64_t size) { HLSSegment *en = av_malloc(sizeof(*en)); const char *filename; @@ -810,24 +906,24 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double if (!en) return AVERROR(ENOMEM); - ret = sls_flags_filename_process(s, hls, en, duration, pos, size); + ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size); if (ret < 0) { return ret; } - filename = av_basename(hls->avf->filename); + filename = av_basename(vs->avf->filename); if (hls->use_localtime_mkdir) { - filename = hls->avf->filename; + filename = vs->avf->filename; } - if ((find_segment_by_filename(hls->segments, filename) || find_segment_by_filename(hls->old_segments, filename)) + if ((find_segment_by_filename(vs->segments, filename) || find_segment_by_filename(vs->old_segments, filename)) && !byterange_mode) { av_log(hls, AV_LOG_WARNING, "Duplicated segment filename detected: %s\n", filename); } av_strlcpy(en->filename, filename, sizeof(en->filename)); - if(hls->has_subtitle) - av_strlcpy(en->sub_filename, av_basename(hls->vtt_avf->filename), sizeof(en->sub_filename)); + if(vs->has_subtitle) + av_strlcpy(en->sub_filename, av_basename(vs->vtt_avf->filename), sizeof(en->sub_filename)); else en->sub_filename[0] = '\0'; @@ -837,9 +933,9 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double en->next = NULL; en->discont = 0; - if (hls->discontinuity) { + if (vs->discontinuity) { en->discont = 1; - hls->discontinuity = 0; + vs->discontinuity = 0; } if (hls->key_info_file || hls->encrypt) { @@ -847,45 +943,45 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double av_strlcpy(en->iv_string, hls->iv_string, sizeof(en->iv_string)); } - if (!hls->segments) - hls->segments = en; + if (!vs->segments) + vs->segments = en; else - hls->last_segment->next = en; + vs->last_segment->next = en; - hls->last_segment = en; + vs->last_segment = en; // EVENT or VOD playlists imply sliding window cannot be used if (hls->pl_type != PLAYLIST_TYPE_NONE) hls->max_nb_segments = 0; - if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { - en = hls->segments; - hls->initial_prog_date_time += en->duration; - hls->segments = en->next; + if (hls->max_nb_segments && vs->nb_entries >= hls->max_nb_segments) { + en = vs->segments; + vs->initial_prog_date_time += en->duration; + vs->segments = en->next; if (en && hls->flags & HLS_DELETE_SEGMENTS && #if FF_API_HLS_WRAP !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) { #else !(hls->flags & HLS_SINGLE_FILE)) { #endif - en->next = hls->old_segments; - hls->old_segments = en; - if ((ret = hls_delete_old_segments(s, hls)) < 0) + en->next = vs->old_segments; + vs->old_segments = en; + if ((ret = hls_delete_old_segments(s, hls, vs)) < 0) return ret; } else av_free(en); } else - hls->nb_entries++; + vs->nb_entries++; if (hls->max_seg_size > 0) { return 0; } - hls->sequence++; + vs->sequence++; return 0; } -static int parse_playlist(AVFormatContext *s, const char *url) +static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs) { HLSContext *hls = s->priv_data; AVIOContext *in; @@ -906,26 +1002,26 @@ static int parse_playlist(AVFormatContext *s, const char *url) goto fail; } - hls->discontinuity = 0; + vs->discontinuity = 0; while (!avio_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { int64_t tmp_sequence = strtoll(ptr, NULL, 10); - if (tmp_sequence < hls->sequence) + if (tmp_sequence < vs->sequence) av_log(hls, AV_LOG_VERBOSE, "Found playlist sequence number was smaller """ "than specified start sequence number: %"PRId64" < %"PRId64", " "omitting\n", tmp_sequence, hls->start_sequence); else { av_log(hls, AV_LOG_DEBUG, "Found playlist sequence number: %"PRId64"\n", tmp_sequence); - hls->sequence = tmp_sequence; + vs->sequence = tmp_sequence; } } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) { is_segment = 1; - hls->discontinuity = 1; + vs->discontinuity = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; - hls->duration = atof(ptr); + vs->duration = atof(ptr); } else if (av_stristart(line, "#EXT-X-KEY:", &ptr)) { ptr = av_stristr(line, "URI=\""); if (ptr) { @@ -954,13 +1050,13 @@ static int parse_playlist(AVFormatContext *s, const char *url) } else if (line[0]) { if (is_segment) { is_segment = 0; - new_start_pos = avio_tell(hls->avf->pb); - hls->size = new_start_pos - hls->start_pos; - av_strlcpy(hls->avf->filename, line, sizeof(line)); - ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); + new_start_pos = avio_tell(vs->avf->pb); + vs->size = new_start_pos - vs->start_pos; + av_strlcpy(vs->avf->filename, line, sizeof(line)); + ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size); if (ret < 0) goto fail; - hls->start_pos = new_start_pos; + vs->start_pos = new_start_pos; } } } @@ -981,19 +1077,6 @@ static void hls_free_segments(HLSSegment *p) } } -static void write_m3u8_head_block(HLSContext *hls, AVIOContext *out, int version, - int target_duration, int64_t sequence) -{ - avio_printf(out, "#EXTM3U\n"); - avio_printf(out, "#EXT-X-VERSION:%d\n", version); - if (hls->allowcache == 0 || hls->allowcache == 1) { - avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES"); - } - avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); - avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); - av_log(hls, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); -} - static void hls_rename_temp_file(AVFormatContext *s, AVFormatContext *oc) { size_t len = strlen(oc->filename); @@ -1005,176 +1088,297 @@ static void hls_rename_temp_file(AVFormatContext *s, AVFormatContext *oc) oc->filename[len-4] = '\0'; } -static int hls_window(AVFormatContext *s, int last) +static int get_relative_url(const char *master_url, const char *media_url, + char *rel_url, int rel_url_buf_size) +{ + char *p = NULL; + int base_len = -1; + p = strrchr(master_url, '/') ? strrchr(master_url, '/') :\ + strrchr(master_url, '\\'); + if (p) { + base_len = FFABS(p - master_url); + if (av_strncasecmp(master_url, media_url, base_len)) { + av_log(NULL, AV_LOG_WARNING, "Unable to find relative url\n"); + return AVERROR(EINVAL); + } + } + av_strlcpy(rel_url, &(media_url[base_len + 1]), rel_url_buf_size); + return 0; +} + +static int create_master_playlist(AVFormatContext *s, + VariantStream * const input_vs) +{ + HLSContext *hls = s->priv_data; + VariantStream *vs, *temp_vs; + AVStream *vid_st, *aud_st; + AVDictionary *options = NULL; + unsigned int i, j; + int m3u8_name_size, ret, bandwidth; + char *m3u8_rel_name; + + input_vs->m3u8_created = 1; + if (!hls->master_m3u8_created) { + /* For the first time, wait until all the media playlists are created */ + for (i = 0; i < hls->nb_varstreams; i++) + if (!hls->var_streams[i].m3u8_created) + return 0; + } else { + /* Keep publishing the master playlist at the configured rate */ + if (&hls->var_streams[0] != input_vs || !hls->master_publish_rate || + input_vs->number % hls->master_publish_rate) + return 0; + } + + set_http_options(s, &options, hls); + + ret = hlsenc_io_open(s, &hls->m3u8_out, hls->master_m3u8_url, &options); + av_dict_free(&options); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open master play list file '%s'\n", + hls->master_m3u8_url); + goto fail; + } + + ff_hls_write_playlist_version(hls->m3u8_out, hls->version); + + /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/ + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &(hls->var_streams[i]); + + if (vs->has_video || vs->has_subtitle || !vs->agroup) + continue; + + m3u8_name_size = strlen(vs->m3u8_name) + 1; + m3u8_rel_name = av_malloc(m3u8_name_size); + if (!m3u8_rel_name) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size); + ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name, + m3u8_rel_name, m3u8_name_size); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n"); + goto fail; + } + + ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, 0, 1); + + av_freep(&m3u8_rel_name); + } + + /* For variant streams with video add #EXT-X-STREAM-INF tag with attributes*/ + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &(hls->var_streams[i]); + + m3u8_name_size = strlen(vs->m3u8_name) + 1; + m3u8_rel_name = av_malloc(m3u8_name_size); + if (!m3u8_rel_name) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size); + ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name, + m3u8_rel_name, m3u8_name_size); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Unable to find relative URL\n"); + goto fail; + } + + vid_st = NULL; + aud_st = NULL; + for (j = 0; j < vs->nb_streams; j++) { + if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + vid_st = vs->streams[j]; + else if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + aud_st = vs->streams[j]; + } + + if (!vid_st && !aud_st) { + av_log(NULL, AV_LOG_WARNING, "Media stream not found\n"); + continue; + } + + /** + * Traverse through the list of audio only rendition streams and find + * the rendition which has highest bitrate in the same audio group + */ + if (vs->agroup) { + for (j = 0; j < hls->nb_varstreams; j++) { + temp_vs = &(hls->var_streams[j]); + if (!temp_vs->has_video && !temp_vs->has_subtitle && + temp_vs->agroup && + !av_strcasecmp(temp_vs->agroup, vs->agroup)) { + if (!aud_st) + aud_st = temp_vs->streams[0]; + if (temp_vs->streams[0]->codecpar->bit_rate > + aud_st->codecpar->bit_rate) + aud_st = temp_vs->streams[0]; + } + } + } + + bandwidth = 0; + if (vid_st) + bandwidth += vid_st->codecpar->bit_rate; + if (aud_st) + bandwidth += aud_st->codecpar->bit_rate; + bandwidth += bandwidth / 10; + + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + aud_st ? vs->agroup : NULL); + + av_freep(&m3u8_rel_name); + } +fail: + if(ret >=0) + hls->master_m3u8_created = 1; + av_freep(&m3u8_rel_name); + hlsenc_io_close(s, &hls->m3u8_out, hls->master_m3u8_url); + return ret; +} + +static int hls_window(AVFormatContext *s, int last, VariantStream *vs) { HLSContext *hls = s->priv_data; HLSSegment *en; int target_duration = 0; int ret = 0; - AVIOContext *out = NULL; - AVIOContext *sub_out = NULL; char temp_filename[1024]; - int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries); - int version = 3; + int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries); const char *proto = avio_find_protocol_name(s->filename); int use_rename = proto && !strcmp(proto, "file"); static unsigned warned_non_file; char *key_uri = NULL; char *iv_string = NULL; AVDictionary *options = NULL; - double prog_date_time = hls->initial_prog_date_time; + double prog_date_time = vs->initial_prog_date_time; + double *prog_date_time_p = (hls->flags & HLS_PROGRAM_DATE_TIME) ? &prog_date_time : NULL; int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); + hls->version = 3; if (byterange_mode) { - version = 4; + hls->version = 4; sequence = 0; } + if (hls->flags & HLS_INDEPENDENT_SEGMENTS) { + hls->version = 6; + } + if (hls->segment_type == SEGMENT_TYPE_FMP4) { - version = 7; + hls->version = 7; } if (!use_rename && !warned_non_file++) av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); set_http_options(s, &options, hls); - snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename); - if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, &options)) < 0) + snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", vs->m3u8_name); + if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) < 0) goto fail; - for (en = hls->segments; en; en = en->next) { + for (en = vs->segments; en; en = en->next) { if (target_duration <= en->duration) - target_duration = get_int_from_double(en->duration); + target_duration = lrint(en->duration); } - hls->discontinuity_set = 0; - write_m3u8_head_block(hls, out, version, target_duration, sequence); - if (hls->pl_type == PLAYLIST_TYPE_EVENT) { - avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); - } else if (hls->pl_type == PLAYLIST_TYPE_VOD) { - avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); - } + vs->discontinuity_set = 0; + ff_hls_write_playlist_header(hls->m3u8_out, hls->version, hls->allowcache, + target_duration, sequence, hls->pl_type); - if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){ - avio_printf(out, "#EXT-X-DISCONTINUITY\n"); - hls->discontinuity_set = 1; + if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){ + avio_printf(hls->m3u8_out, "#EXT-X-DISCONTINUITY\n"); + vs->discontinuity_set = 1; } - for (en = hls->segments; en; en = en->next) { + if (vs->has_video && (hls->flags & HLS_INDEPENDENT_SEGMENTS)) { + avio_printf(hls->m3u8_out, "#EXT-X-INDEPENDENT-SEGMENTS\n"); + } + for (en = vs->segments; en; en = en->next) { if ((hls->encrypt || hls->key_info_file) && (!key_uri || strcmp(en->key_uri, key_uri) || av_strcasecmp(en->iv_string, iv_string))) { - avio_printf(out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri); + avio_printf(hls->m3u8_out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri); if (*en->iv_string) - avio_printf(out, ",IV=0x%s", en->iv_string); - avio_printf(out, "\n"); + avio_printf(hls->m3u8_out, ",IV=0x%s", en->iv_string); + avio_printf(hls->m3u8_out, "\n"); key_uri = en->key_uri; iv_string = en->iv_string; } - if (en->discont) { - avio_printf(out, "#EXT-X-DISCONTINUITY\n"); + if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) { + ff_hls_write_init_file(hls->m3u8_out, vs->fmp4_init_filename, + hls->flags & HLS_SINGLE_FILE, en->size, en->pos); } - if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == hls->segments)) { - avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", hls->fmp4_init_filename); - if (hls->flags & HLS_SINGLE_FILE) { - avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", en->size, en->pos); - } - avio_printf(out, "\n"); - } else { - if (hls->flags & HLS_ROUND_DURATIONS) - avio_printf(out, "#EXTINF:%ld,\n", lrint(en->duration)); - else - avio_printf(out, "#EXTINF:%f,\n", en->duration); - if (byterange_mode) - avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", - en->size, en->pos); - } - if (hls->flags & HLS_PROGRAM_DATE_TIME) { - time_t tt, wrongsecs; - int milli; - struct tm *tm, tmpbuf; - char buf0[128], buf1[128]; - tt = (int64_t)prog_date_time; - milli = av_clip(lrint(1000*(prog_date_time - tt)), 0, 999); - tm = localtime_r(&tt, &tmpbuf); - strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm); - if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') { - int tz_min, dst = tm->tm_isdst; - tm = gmtime_r(&tt, &tmpbuf); - tm->tm_isdst = dst; - wrongsecs = mktime(tm); - tz_min = (abs(wrongsecs - tt) + 30) / 60; - snprintf(buf1, sizeof(buf1), - "%c%02d%02d", - wrongsecs <= tt ? '+' : '-', - tz_min / 60, - tz_min % 60); - } - avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1); - prog_date_time += en->duration; - } - if (!((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == hls->segments))) { - if (hls->baseurl) - avio_printf(out, "%s", hls->baseurl); - avio_printf(out, "%s\n", en->filename); + ret = ff_hls_write_file_entry(hls->m3u8_out, en->discont, byterange_mode, + en->duration, hls->flags & HLS_ROUND_DURATIONS, + en->size, en->pos, vs->baseurl, + en->filename, prog_date_time_p); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } } if (last && (hls->flags & HLS_OMIT_ENDLIST)==0) - avio_printf(out, "#EXT-X-ENDLIST\n"); + ff_hls_write_end_list(hls->m3u8_out); - if( hls->vtt_m3u8_name ) { - if ((ret = s->io_open(s, &sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE, &options)) < 0) + if( vs->vtt_m3u8_name ) { + if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name, &options)) < 0) goto fail; - write_m3u8_head_block(hls, sub_out, version, target_duration, sequence); - - for (en = hls->segments; en; en = en->next) { - avio_printf(sub_out, "#EXTINF:%f,\n", en->duration); - if (byterange_mode) - avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", - en->size, en->pos); - if (hls->baseurl) - avio_printf(sub_out, "%s", hls->baseurl); - avio_printf(sub_out, "%s\n", en->sub_filename); + ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache, + target_duration, sequence, PLAYLIST_TYPE_NONE); + for (en = vs->segments; en; en = en->next) { + ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode, + en->duration, 0, en->size, en->pos, + vs->baseurl, en->sub_filename, NULL); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); + } } if (last) - avio_printf(sub_out, "#EXT-X-ENDLIST\n"); + ff_hls_write_end_list(hls->sub_m3u8_out); } fail: av_dict_free(&options); - ff_format_io_close(s, &out); - ff_format_io_close(s, &sub_out); + hlsenc_io_close(s, &hls->m3u8_out, temp_filename); + hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name); if (ret >= 0 && use_rename) - ff_rename(temp_filename, s->filename, s); + ff_rename(temp_filename, vs->m3u8_name, s); + + if (ret >= 0 && hls->master_pl_name) + if (create_master_playlist(s, vs) < 0) + av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n"); + return ret; } -static int hls_start(AVFormatContext *s) +static int hls_start(AVFormatContext *s, VariantStream *vs) { HLSContext *c = s->priv_data; - AVFormatContext *oc = c->avf; - AVFormatContext *vtt_oc = c->vtt_avf; + AVFormatContext *oc = vs->avf; + AVFormatContext *vtt_oc = vs->vtt_avf; AVDictionary *options = NULL; char *filename, iv_string[KEYSIZE*2 + 1]; int err = 0; if (c->flags & HLS_SINGLE_FILE) { - av_strlcpy(oc->filename, c->basename, + av_strlcpy(oc->filename, vs->basename, sizeof(oc->filename)); - if (c->vtt_basename) - av_strlcpy(vtt_oc->filename, c->vtt_basename, + if (vs->vtt_basename) + av_strlcpy(vtt_oc->filename, vs->vtt_basename, sizeof(vtt_oc->filename)); } else if (c->max_seg_size > 0) { if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), #if FF_API_HLS_WRAP - c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + vs->basename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - c->basename, 'd', c->sequence) < 1) { + vs->basename, 'd', vs->sequence) < 1) { #endif - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", vs->basename); return AVERROR(EINVAL); } } else { @@ -1183,12 +1387,12 @@ static int hls_start(AVFormatContext *s) struct tm *tm, tmpbuf; time(&now0); tm = localtime_r(&now0, &tmpbuf); - if (!strftime(oc->filename, sizeof(oc->filename), c->basename, tm)) { + if (!strftime(oc->filename, sizeof(oc->filename), vs->basename, tm)) { av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n"); return AVERROR(EINVAL); } - err = sls_flag_use_localtime_filename(oc, c); + err = sls_flag_use_localtime_filename(oc, c, vs); if (err < 0) { return AVERROR(ENOMEM); } @@ -1209,26 +1413,26 @@ static int hls_start(AVFormatContext *s) } } else if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), #if FF_API_HLS_WRAP - c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + vs->basename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - c->basename, 'd', c->sequence) < 1) { + vs->basename, 'd', vs->sequence) < 1) { #endif - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", vs->basename); return AVERROR(EINVAL); } - if( c->vtt_basename) { + if( vs->vtt_basename) { if (replace_int_data_in_filename(vtt_oc->filename, sizeof(vtt_oc->filename), #if FF_API_HLS_WRAP - c->vtt_basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + vs->vtt_basename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - c->vtt_basename, 'd', c->sequence) < 1) { + vs->vtt_basename, 'd', vs->sequence) < 1) { #endif - av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename); + av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", vs->vtt_basename); return AVERROR(EINVAL); } } } - c->number++; + vs->number++; set_http_options(s, &options, c); @@ -1242,21 +1446,22 @@ static int hls_start(AVFormatContext *s) " will use -hls_key_info_file priority\n"); } - if (c->number <= 1 || (c->flags & HLS_PERIODIC_REKEY)) { + if (!c->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) { if (c->key_info_file) { if ((err = hls_encryption_start(s)) < 0) goto fail; } else { - if ((err = do_encrypt(s)) < 0) + if ((err = do_encrypt(s, vs)) < 0) goto fail; } + c->encrypt_started = 1; } if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0)) < 0) goto fail; err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string)); if (!err) - snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, c->sequence); + snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence); if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0) goto fail; @@ -1265,24 +1470,23 @@ static int hls_start(AVFormatContext *s) err = AVERROR(ENOMEM); goto fail; } - err = s->io_open(s, &oc->pb, filename, AVIO_FLAG_WRITE, &options); + err = hlsenc_io_open(s, &oc->pb, filename, &options); av_free(filename); av_dict_free(&options); if (err < 0) return err; - } else - if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, &options)) < 0) + } else if (c->segment_type != SEGMENT_TYPE_FMP4) { + if ((err = hlsenc_io_open(s, &oc->pb, oc->filename, &options)) < 0) goto fail; - if (c->vtt_basename) { + } + if (vs->vtt_basename) { set_http_options(s, &options, c); - if ((err = s->io_open(s, &vtt_oc->pb, vtt_oc->filename, AVIO_FLAG_WRITE, &options)) < 0) + if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->filename, &options)) < 0) goto fail; } av_dict_free(&options); - if (c->segment_type == SEGMENT_TYPE_FMP4 && !(c->flags & HLS_SINGLE_FILE)) { - write_styp(oc->pb); - } else { + if (c->segment_type != SEGMENT_TYPE_FMP4) { /* We only require one PAT/PMT per segment. */ if (oc->oformat->priv_class && oc->priv_data) { char period[21]; @@ -1295,7 +1499,7 @@ static int hls_start(AVFormatContext *s) } } - if (c->vtt_basename) { + if (vs->vtt_basename) { err = avformat_write_header(vtt_oc,NULL); if (err < 0) return err; @@ -1324,17 +1528,675 @@ static const char * get_default_pattern_localtime_fmt(AVFormatContext *s) return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, "%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts"; } +static int append_postfix(char *name, int name_buf_len, int i) +{ + char *p; + char extension[10] = {'\0'}; + + p = strrchr(name, '.'); + if (p) { + av_strlcpy(extension, p, sizeof(extension)); + *p = '\0'; + } + + snprintf(name + strlen(name), name_buf_len - strlen(name), POSTFIX_PATTERN, i); + + if (strlen(extension)) + av_strlcat(name, extension, name_buf_len); + + return 0; +} + +static int validate_name(int nb_vs, const char *fn) +{ + const char *filename, *subdir_name; + char *fn_dup = NULL; + int ret = 0; + + if (!fn) { + ret = AVERROR(EINVAL); + goto fail; + } + + fn_dup = av_strdup(fn); + if (!fn_dup) { + ret = AVERROR(ENOMEM); + goto fail; + } + + filename = av_basename(fn); + subdir_name = av_dirname(fn_dup); + + if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, "%v")) { + av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected in the filename %s\n", + fn); + ret = AVERROR(EINVAL); + goto fail; + } + + if (av_stristr(filename, "%v") && av_stristr(subdir_name, "%v")) { + av_log(NULL, AV_LOG_ERROR, "%%v is expected either in filename or in the sub-directory name of file %s\n", + fn); + ret = AVERROR(EINVAL); + goto fail; + } + +fail: + av_freep(&fn_dup); + return ret; +} + +static int format_name(char *buf, int buf_len, int index) +{ + const char *proto, *dir; + char *orig_buf_dup = NULL, *mod_buf_dup = NULL; + int ret = 0; + + if (!av_stristr(buf, "%v")) + return ret; + + orig_buf_dup = av_strdup(buf); + if (!orig_buf_dup) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (replace_int_data_in_filename(buf, buf_len, orig_buf_dup, 'v', index) < 1) { + ret = AVERROR(EINVAL); + goto fail; + } + + proto = avio_find_protocol_name(orig_buf_dup); + dir = av_dirname(orig_buf_dup); + + /* if %v is present in the file's directory, create sub-directory */ + if (av_stristr(dir, "%v") && proto && !strcmp(proto, "file")) { + mod_buf_dup = av_strdup(buf); + if (!mod_buf_dup) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dir = av_dirname(mod_buf_dup); + if (mkdir_p(dir) == -1 && errno != EEXIST) { + ret = AVERROR(errno); + goto fail; + } + } + +fail: + av_freep(&orig_buf_dup); + av_freep(&mod_buf_dup); + return ret; +} + +static int get_nth_codec_stream_index(AVFormatContext *s, + enum AVMediaType codec_type, + int stream_id) +{ + unsigned int stream_index, cnt; + if (stream_id < 0 || stream_id > s->nb_streams - 1) + return -1; + cnt = 0; + for (stream_index = 0; stream_index < s->nb_streams; stream_index++) { + if (s->streams[stream_index]->codecpar->codec_type != codec_type) + continue; + if (cnt == stream_id) + return stream_index; + cnt++; + } + return -1; +} + +static int parse_variant_stream_mapstring(AVFormatContext *s) +{ + HLSContext *hls = s->priv_data; + VariantStream *vs; + int stream_index; + enum AVMediaType codec_type; + int nb_varstreams, nb_streams; + char *p, *q, *saveptr1, *saveptr2, *varstr, *keyval; + const char *val; + + /** + * Expected format for var_stream_map string is as below: + * "a:0,v:0 a:1,v:1" + * "a:0,agroup:a0 a:1,agroup:a1 v:0,agroup:a0 v:1,agroup:a1" + * This string specifies how to group the audio, video and subtitle streams + * into different variant streams. The variant stream groups are separated + * by space. + * + * a:, v:, s: are keys to specify audio, video and subtitle streams + * respectively. Allowed values are 0 to 9 digits (limited just based on + * practical usage) + * + * agroup: is key to specify audio group. A string can be given as value. + */ + p = av_strdup(hls->var_stream_map); + q = p; + while(av_strtok(q, " \t", &saveptr1)) { + q = NULL; + hls->nb_varstreams++; + } + av_freep(&p); + + hls->var_streams = av_mallocz(sizeof(*hls->var_streams) * hls->nb_varstreams); + if (!hls->var_streams) + return AVERROR(ENOMEM); + + p = hls->var_stream_map; + nb_varstreams = 0; + while (varstr = av_strtok(p, " \t", &saveptr1)) { + p = NULL; + + if (nb_varstreams < hls->nb_varstreams) + vs = &(hls->var_streams[nb_varstreams++]); + else + return AVERROR(EINVAL); + + q = varstr; + while (q < varstr + strlen(varstr)) { + if (!av_strncasecmp(q, "a:", 2) || !av_strncasecmp(q, "v:", 2) || + !av_strncasecmp(q, "s:", 2)) + vs->nb_streams++; + q++; + } + vs->streams = av_mallocz(sizeof(AVStream *) * vs->nb_streams); + if (!vs->streams) + return AVERROR(ENOMEM); + + nb_streams = 0; + while (keyval = av_strtok(varstr, ",", &saveptr2)) { + varstr = NULL; + + if (av_strstart(keyval, "agroup:", &val)) { + vs->agroup = av_strdup(val); + if (!vs->agroup) + return AVERROR(ENOMEM); + continue; + } else if (av_strstart(keyval, "v:", &val)) { + codec_type = AVMEDIA_TYPE_VIDEO; + } else if (av_strstart(keyval, "a:", &val)) { + codec_type = AVMEDIA_TYPE_AUDIO; + } else if (av_strstart(keyval, "s:", &val)) { + codec_type = AVMEDIA_TYPE_SUBTITLE; + } else { + av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval); + return AVERROR(EINVAL); + } + + stream_index = -1; + if (av_isdigit(*val)) + stream_index = get_nth_codec_stream_index (s, codec_type, + atoi(val)); + + if (stream_index >= 0 && nb_streams < vs->nb_streams) { + vs->streams[nb_streams++] = s->streams[stream_index]; + } else { + av_log(s, AV_LOG_ERROR, "Unable to map stream at %s\n", keyval); + return AVERROR(EINVAL); + } + } + } + av_log(s, AV_LOG_DEBUG, "Number of variant streams %d\n", + hls->nb_varstreams); + + return 0; +} + +static int update_variant_stream_info(AVFormatContext *s) { + HLSContext *hls = s->priv_data; + unsigned int i; + + if (hls->var_stream_map) { + return parse_variant_stream_mapstring(s); + } else { + //By default, a single variant stream with all the codec streams is created + hls->nb_varstreams = 1; + hls->var_streams = av_mallocz(sizeof(*hls->var_streams) * + hls->nb_varstreams); + if (!hls->var_streams) + return AVERROR(ENOMEM); + + hls->var_streams[0].nb_streams = s->nb_streams; + hls->var_streams[0].streams = av_mallocz(sizeof(AVStream *) * + hls->var_streams[0].nb_streams); + if (!hls->var_streams[0].streams) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_streams; i++) + hls->var_streams[0].streams[i] = s->streams[i]; + } + return 0; +} + +static int update_master_pl_info(AVFormatContext *s) { + HLSContext *hls = s->priv_data; + const char *dir; + char *fn1= NULL, *fn2 = NULL; + int ret = 0; + + fn1 = av_strdup(s->filename); + if (!fn1) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dir = av_dirname(fn1); + + /** + * if output file's directory has %v, variants are created in sub-directories + * then master is created at the sub-directories level + */ + if (dir && av_stristr(av_basename(dir), "%v")) { + fn2 = av_strdup(dir); + if (!fn2) { + ret = AVERROR(ENOMEM); + goto fail; + } + dir = av_dirname(fn2); + } + + if (dir && strcmp(dir, ".")) + hls->master_m3u8_url = av_append_path_component(dir, hls->master_pl_name); + else + hls->master_m3u8_url = av_strdup(hls->master_pl_name); + + if (!hls->master_m3u8_url) { + ret = AVERROR(ENOMEM); + goto fail; + } + +fail: + av_freep(&fn1); + av_freep(&fn2); + + return ret; +} + static int hls_write_header(AVFormatContext *s) { HLSContext *hls = s->priv_data; - int ret, i; - char *p = NULL; + int ret, i, j; + AVDictionary *options = NULL; + VariantStream *vs = NULL; + + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + + av_dict_copy(&options, hls->format_options, 0); + ret = avformat_write_header(vs->avf, &options); + if (av_dict_count(options)) { + av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str); + ret = AVERROR(EINVAL); + av_dict_free(&options); + goto fail; + } + av_dict_free(&options); + //av_assert0(s->nb_streams == hls->avf->nb_streams); + for (j = 0; j < vs->nb_streams; j++) { + AVStream *inner_st; + AVStream *outer_st = vs->streams[j]; + + if (hls->max_seg_size > 0) { + if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && + (outer_st->codecpar->bit_rate > hls->max_seg_size)) { + av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, " + "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.", + outer_st->codecpar->bit_rate, hls->max_seg_size); + } + } + + if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) + inner_st = vs->avf->streams[j]; + else if (vs->vtt_avf) + inner_st = vs->vtt_avf->streams[0]; + else { + /* We have a subtitle stream, when the user does not want one */ + inner_st = NULL; + continue; + } + avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den); + } + } +fail: + + return ret; +} + +static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + HLSContext *hls = s->priv_data; + AVFormatContext *oc = NULL; + AVStream *st = s->streams[pkt->stream_index]; + int64_t end_pts = 0; + int is_ref_pkt = 1; + int ret = 0, can_split = 1, i, j; + int stream_index = 0; + int range_length = 0; + uint8_t *buffer = NULL; + VariantStream *vs = NULL; + + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + for (j = 0; j < vs->nb_streams; j++) { + if (vs->streams[j] == st) { + if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) { + oc = vs->vtt_avf; + stream_index = 0; + } else { + oc = vs->avf; + stream_index = j; + } + break; + } + } + + if (oc) + break; + } + + if (!oc) { + av_log(s, AV_LOG_ERROR, "Unable to find mapping variant stream\n"); + return AVERROR(ENOMEM); + } + + end_pts = hls->recording_time * vs->number; + + if (vs->sequence - vs->nb_entries > hls->start_sequence && hls->init_time > 0) { + /* reset end_pts, hls->recording_time at end of the init hls list */ + int init_list_dur = hls->init_time * vs->nb_entries * AV_TIME_BASE; + int after_init_list_dur = (vs->sequence - vs->nb_entries ) * hls->time * AV_TIME_BASE; + hls->recording_time = hls->time * AV_TIME_BASE; + end_pts = init_list_dur + after_init_list_dur ; + } + + if (vs->start_pts == AV_NOPTS_VALUE) { + vs->start_pts = pkt->pts; + } + + if (vs->has_video) { + can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME)); + is_ref_pkt = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; + } + if (pkt->pts == AV_NOPTS_VALUE) + is_ref_pkt = can_split = 0; + + if (is_ref_pkt) { + if (vs->end_pts == AV_NOPTS_VALUE) + vs->end_pts = pkt->pts; + if (vs->new_start) { + vs->new_start = 0; + vs->duration = (double)(pkt->pts - vs->end_pts) + * st->time_base.num / st->time_base.den; + vs->dpp = (double)(pkt->duration) * st->time_base.num / st->time_base.den; + } else { + if (pkt->duration) { + vs->duration += (double)(pkt->duration) * st->time_base.num / st->time_base.den; + } else { + av_log(s, AV_LOG_WARNING, "pkt->duration = 0, maybe the hls segment duration will not precise\n"); + vs->duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; + } + } + + } + + if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base, + end_pts, AV_TIME_BASE_Q) >= 0) { + int64_t new_start_pos; + char *old_filename = av_strdup(vs->avf->filename); + int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); + + if (!old_filename) { + return AVERROR(ENOMEM); + } + + av_write_frame(vs->avf, NULL); /* Flush any buffered data */ + + new_start_pos = avio_tell(vs->avf->pb); + vs->size = new_start_pos - vs->start_pos; + + if (!byterange_mode) { + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + if (!vs->init_range_length) { + avio_flush(oc->pb); + range_length = avio_close_dyn_buf(oc->pb, &buffer); + avio_write(vs->out, buffer, range_length); + vs->init_range_length = range_length; + avio_open_dyn_buf(&oc->pb); + vs->packets_written = 0; + ff_format_io_close(s, &vs->out); + hlsenc_io_close(s, &vs->out, vs->base_output_dirname); + } + } else { + hlsenc_io_close(s, &oc->pb, oc->filename); + } + if (vs->vtt_avf) { + hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->filename); + } + } + if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { + if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0)) + if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4) + av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0); + hls_rename_temp_file(s, oc); + } + + if (vs->fmp4_init_mode) { + vs->number--; + } + + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + ret = hlsenc_io_open(s, &vs->out, vs->avf->filename, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open file '%s'\n", + vs->avf->filename); + av_free(old_filename); + return ret; + } + write_styp(vs->out); + ret = flush_dynbuf(vs, &range_length); + if (ret < 0) { + av_free(old_filename); + return ret; + } + ff_format_io_close(s, &vs->out); + } + ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size); + vs->start_pos = new_start_pos; + if (ret < 0) { + av_free(old_filename); + return ret; + } + + vs->end_pts = pkt->pts; + vs->duration = 0; + + vs->fmp4_init_mode = 0; + if (hls->flags & HLS_SINGLE_FILE) { + vs->number++; + } else if (hls->max_seg_size > 0) { + if (vs->start_pos >= hls->max_seg_size) { + vs->sequence++; + sls_flag_file_rename(hls, vs, old_filename); + ret = hls_start(s, vs); + vs->start_pos = 0; + /* When split segment by byte, the duration is short than hls_time, + * so it is not enough one segment duration as hls_time, */ + vs->number--; + } + vs->number++; + } else { + sls_flag_file_rename(hls, vs, old_filename); + ret = hls_start(s, vs); + } + av_free(old_filename); + + if (ret < 0) { + return ret; + } + + if (!vs->fmp4_init_mode || byterange_mode) + if ((ret = hls_window(s, 0, vs)) < 0) { + return ret; + } + } + + vs->packets_written++; + ret = ff_write_chained(oc, stream_index, pkt, s, 0); + + return ret; +} + +static int hls_write_trailer(struct AVFormatContext *s) +{ + HLSContext *hls = s->priv_data; + AVFormatContext *oc = NULL; + AVFormatContext *vtt_oc = NULL; + char *old_filename = NULL; + int i; + int ret = 0; + VariantStream *vs = NULL; + + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + + oc = vs->avf; + vtt_oc = vs->vtt_avf; + old_filename = av_strdup(vs->avf->filename); + + if (!old_filename) { + return AVERROR(ENOMEM); + } + if ( hls->segment_type == SEGMENT_TYPE_FMP4) { + int range_length = 0; + ret = hlsenc_io_open(s, &vs->out, vs->avf->filename, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->filename); + goto failed; + } + write_styp(vs->out); + ret = flush_dynbuf(vs, &range_length); + if (ret < 0) { + goto failed; + } + ff_format_io_close(s, &vs->out); + } + +failed: + av_write_trailer(oc); + if (oc->pb) { + vs->size = avio_tell(vs->avf->pb) - vs->start_pos; + if (hls->segment_type != SEGMENT_TYPE_FMP4) + ff_format_io_close(s, &oc->pb); + + if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { + hls_rename_temp_file(s, oc); + } + + /* after av_write_trailer, then duration + 1 duration per packet */ + hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size); + } + + sls_flag_file_rename(hls, vs, old_filename); + + if (vtt_oc) { + if (vtt_oc->pb) + av_write_trailer(vtt_oc); + vs->size = avio_tell(vs->vtt_avf->pb) - vs->start_pos; + ff_format_io_close(s, &vtt_oc->pb); + } + av_freep(&vs->basename); + av_freep(&vs->base_output_dirname); + avformat_free_context(oc); + + vs->avf = NULL; + hls_window(s, 1, vs); + + av_freep(&vs->fmp4_init_filename); + if (vtt_oc) { + av_freep(&vs->vtt_basename); + av_freep(&vs->vtt_m3u8_name); + avformat_free_context(vtt_oc); + } + + hls_free_segments(vs->segments); + hls_free_segments(vs->old_segments); + av_free(old_filename); + av_freep(&vs->m3u8_name); + av_freep(&vs->streams); + av_freep(&vs->agroup); + av_freep(&vs->baseurl); + } + + ff_format_io_close(s, &hls->m3u8_out); + ff_format_io_close(s, &hls->sub_m3u8_out); + av_freep(&hls->key_basename); + av_freep(&hls->var_streams); + av_freep(&hls->master_m3u8_url); + return 0; +} + + +static int hls_init(AVFormatContext *s) +{ + int ret = 0; + int i = 0; + int j = 0; + HLSContext *hls = s->priv_data; const char *pattern = "%d.ts"; + VariantStream *vs = NULL; + int basename_size = 0; const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s); const char *vtt_pattern = "%d.vtt"; - AVDictionary *options = NULL; - int basename_size = 0; + char *p = NULL; int vtt_basename_size = 0; + int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; + + ret = update_variant_stream_info(s); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n", + ret); + goto fail; + } + //TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present + if (hls->nb_varstreams > 1 && hls->flags & HLS_PERIODIC_REKEY) { + ret = AVERROR(EINVAL); + av_log(s, AV_LOG_ERROR, "Periodic re-key not supported when more than one variant streams are present\n"); + goto fail; + } + + ret = validate_name(hls->nb_varstreams, s->filename); + if (ret < 0) + goto fail; + + if (hls->segment_filename) { + ret = validate_name(hls->nb_varstreams, hls->segment_filename); + if (ret < 0) + goto fail; + } + + if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { + ret = validate_name(hls->nb_varstreams, hls->fmp4_init_filename); + if (ret < 0) + goto fail; + } + + if (hls->subtitle_filename) { + ret = validate_name(hls->nb_varstreams, hls->subtitle_filename); + if (ret < 0) + goto fail; + } + + if (hls->master_pl_name) { + ret = update_master_pl_info(s); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n", + ret); + goto fail; + } + } if (hls->segment_type == SEGMENT_TYPE_FMP4) { pattern = "%d.m4s"; @@ -1356,422 +2218,271 @@ static int hls_write_header(AVFormatContext *s) av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence); } - hls->sequence = hls->start_sequence; hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE; - hls->start_pts = AV_NOPTS_VALUE; - hls->current_segment_final_filename_fmt[0] = '\0'; + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; - if (hls->flags & HLS_PROGRAM_DATE_TIME) { - time_t now0; - time(&now0); - hls->initial_prog_date_time = now0; - } - - if (hls->format_options_str) { - ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); - if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str); + vs->m3u8_name = av_strdup(s->filename); + if (!vs->m3u8_name ) { + ret = AVERROR(ENOMEM); goto fail; } - } + ret = format_name(vs->m3u8_name, strlen(s->filename) + 1, i); + if (ret < 0) + goto fail; - for (i = 0; i < s->nb_streams; i++) { - hls->has_video += - s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; - hls->has_subtitle += - s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE; - } + vs->sequence = hls->start_sequence; + vs->start_pts = AV_NOPTS_VALUE; + vs->end_pts = AV_NOPTS_VALUE; + vs->current_segment_final_filename_fmt[0] = '\0'; - if (hls->has_video > 1) - av_log(s, AV_LOG_WARNING, - "More than a single video stream present, " - "expect issues decoding it.\n"); + if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) { + // Independent segments cannot be guaranteed when splitting by time + hls->flags &= ~HLS_INDEPENDENT_SEGMENTS; + av_log(s, AV_LOG_WARNING, + "'split_by_time' and 'independent_segments' cannot be enabled together. " + "Disabling 'independent_segments' flag\n"); + } - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - hls->oformat = av_guess_format("mp4", NULL, NULL); - } else { - hls->oformat = av_guess_format("mpegts", NULL, NULL); - } + if (hls->flags & HLS_PROGRAM_DATE_TIME) { + time_t now0; + time(&now0); + vs->initial_prog_date_time = now0; + } + if (hls->format_options_str) { + ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str); + goto fail; + } + } - if (!hls->oformat) { - ret = AVERROR_MUXER_NOT_FOUND; - goto fail; - } + for (j = 0; j < vs->nb_streams; j++) { + vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; + vs->has_subtitle += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE; + } - if(hls->has_subtitle) { - hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL); - if (!hls->oformat) { + if (vs->has_video > 1) + av_log(s, AV_LOG_WARNING, "More than a single video stream present, expect issues decoding it.\n"); + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + vs->oformat = av_guess_format("mp4", NULL, NULL); + } else { + vs->oformat = av_guess_format("mpegts", NULL, NULL); + } + + if (!vs->oformat) { ret = AVERROR_MUXER_NOT_FOUND; goto fail; } - } - if (hls->segment_filename) { - hls->basename = av_strdup(hls->segment_filename); - if (!hls->basename) { - ret = AVERROR(ENOMEM); - goto fail; + if (vs->has_subtitle) { + vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL); + if (!vs->oformat) { + ret = AVERROR_MUXER_NOT_FOUND; + goto fail; + } } - } else { - if (hls->flags & HLS_SINGLE_FILE) { - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - pattern = ".m4s"; + if (hls->segment_filename) { + basename_size = strlen(hls->segment_filename) + 1; + vs->basename = av_malloc(basename_size); + if (!vs->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(vs->basename, hls->segment_filename, basename_size); + ret = format_name(vs->basename, basename_size, i); + if (ret < 0) + goto fail; + } else { + if (hls->flags & HLS_SINGLE_FILE) { + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + pattern = ".m4s"; + } else { + pattern = ".ts"; + } + } + + if (hls->use_localtime) { + basename_size = strlen(vs->m3u8_name) + strlen(pattern_localtime_fmt) + 1; } else { - pattern = ".ts"; + basename_size = strlen(vs->m3u8_name) + strlen(pattern) + 1; + } + + vs->basename = av_malloc(basename_size); + if (!vs->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(vs->basename, vs->m3u8_name, basename_size); + + p = strrchr(vs->basename, '.'); + if (p) + *p = '\0'; + if (hls->use_localtime) { + av_strlcat(vs->basename, pattern_localtime_fmt, basename_size); + } else { + av_strlcat(vs->basename, pattern, basename_size); } } - if (hls->use_localtime) { - basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1; - } else { - basename_size = strlen(s->filename) + strlen(pattern) + 1; - } - hls->basename = av_malloc(basename_size); - if (!hls->basename) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + if (hls->nb_varstreams > 1) + fmp4_init_filename_len += strlen(POSTFIX_PATTERN); + vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len); + if (!vs->fmp4_init_filename ) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename, + fmp4_init_filename_len); - av_strlcpy(hls->basename, s->filename, basename_size); + if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { + ret = format_name(vs->fmp4_init_filename, fmp4_init_filename_len, i); + if (ret < 0) + goto fail; - p = strrchr(hls->basename, '.'); - if (p) - *p = '\0'; - if (hls->use_localtime) { - av_strlcat(hls->basename, pattern_localtime_fmt, basename_size); - } else { - av_strlcat(hls->basename, pattern, basename_size); - } - } + fmp4_init_filename_len = strlen(vs->fmp4_init_filename) + 1; + vs->base_output_dirname = av_malloc(fmp4_init_filename_len); + if (!vs->base_output_dirname) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename, + fmp4_init_filename_len); + } else { + if (hls->nb_varstreams > 1) { + ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i); + if (ret < 0) + goto fail; + } - if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { - int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; - hls->base_output_dirname = av_malloc(fmp4_init_filename_len); - if (!hls->base_output_dirname) { - ret = AVERROR(ENOMEM); - goto fail; - } - av_strlcpy(hls->base_output_dirname, hls->fmp4_init_filename, fmp4_init_filename_len); - } else { - hls->base_output_dirname = av_malloc(basename_size); - if (!hls->base_output_dirname) { - ret = AVERROR(ENOMEM); - goto fail; - } + fmp4_init_filename_len = strlen(vs->m3u8_name) + + strlen(vs->fmp4_init_filename) + 1; - av_strlcpy(hls->base_output_dirname, s->filename, basename_size); - p = strrchr(hls->base_output_dirname, '/'); - if (p) { - *(p + 1) = '\0'; - av_strlcat(hls->base_output_dirname, hls->fmp4_init_filename, basename_size); - } else { - av_strlcpy(hls->base_output_dirname, hls->fmp4_init_filename, basename_size); - } - } + vs->base_output_dirname = av_malloc(fmp4_init_filename_len); + if (!vs->base_output_dirname) { + ret = AVERROR(ENOMEM); + goto fail; + } - if (!hls->use_localtime) { - ret = sls_flag_check_duration_size_index(hls); - if (ret < 0) { - goto fail; - } - } else { - ret = sls_flag_check_duration_size(hls); - if (ret < 0) { - goto fail; - } - } - if(hls->has_subtitle) { - - if (hls->flags & HLS_SINGLE_FILE) - vtt_pattern = ".vtt"; - vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1; - hls->vtt_basename = av_malloc(vtt_basename_size); - if (!hls->vtt_basename) { - ret = AVERROR(ENOMEM); - goto fail; - } - hls->vtt_m3u8_name = av_malloc(vtt_basename_size); - if (!hls->vtt_m3u8_name ) { - ret = AVERROR(ENOMEM); - goto fail; - } - av_strlcpy(hls->vtt_basename, s->filename, vtt_basename_size); - p = strrchr(hls->vtt_basename, '.'); - if (p) - *p = '\0'; - - if( hls->subtitle_filename ) { - strcpy(hls->vtt_m3u8_name, hls->subtitle_filename); - } else { - strcpy(hls->vtt_m3u8_name, hls->vtt_basename); - av_strlcat(hls->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size); - } - av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size); - } - - if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) { - hls->fmp4_init_filename = av_strdup(hls->basename); - if (!hls->fmp4_init_filename) { - ret = AVERROR(ENOMEM); - goto fail; - } - } - - if ((ret = hls_mux_init(s)) < 0) - goto fail; - - if (hls->flags & HLS_APPEND_LIST) { - parse_playlist(s, s->filename); - hls->discontinuity = 1; - if (hls->init_time > 0) { - av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time," - " hls_init_time value will have no effect\n"); - hls->init_time = 0; - hls->recording_time = hls->time * AV_TIME_BASE; - } - } - - if (hls->segment_type != SEGMENT_TYPE_FMP4 || hls->flags & HLS_SINGLE_FILE) { - if ((ret = hls_start(s)) < 0) - goto fail; - } - - av_dict_copy(&options, hls->format_options, 0); - ret = avformat_write_header(hls->avf, &options); - if (av_dict_count(options)) { - av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str); - ret = AVERROR(EINVAL); - goto fail; - } - //av_assert0(s->nb_streams == hls->avf->nb_streams); - for (i = 0; i < s->nb_streams; i++) { - AVStream *inner_st; - AVStream *outer_st = s->streams[i]; - - if (hls->max_seg_size > 0) { - if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && - (outer_st->codecpar->bit_rate > hls->max_seg_size)) { - av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, " - "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.", - outer_st->codecpar->bit_rate, hls->max_seg_size); + av_strlcpy(vs->base_output_dirname, vs->m3u8_name, + fmp4_init_filename_len); + p = strrchr(vs->base_output_dirname, '/'); + if (p) { + *(p + 1) = '\0'; + av_strlcat(vs->base_output_dirname, vs->fmp4_init_filename, + fmp4_init_filename_len); + } else { + av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename, + fmp4_init_filename_len); + } } } - if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) - inner_st = hls->avf->streams[i]; - else if (hls->vtt_avf) - inner_st = hls->vtt_avf->streams[0]; - else { - /* We have a subtitle stream, when the user does not want one */ - inner_st = NULL; - continue; + if (!hls->use_localtime) { + ret = sls_flag_check_duration_size_index(hls); + if (ret < 0) { + goto fail; + } + } else { + ret = sls_flag_check_duration_size(hls, vs); + if (ret < 0) { + goto fail; + } } - avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den); + if (vs->has_subtitle) { + + if (hls->flags & HLS_SINGLE_FILE) + vtt_pattern = ".vtt"; + vtt_basename_size = strlen(vs->m3u8_name) + strlen(vtt_pattern) + 1; + + vs->vtt_basename = av_malloc(vtt_basename_size); + if (!vs->vtt_basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + vs->vtt_m3u8_name = av_malloc(vtt_basename_size); + if (!vs->vtt_m3u8_name ) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(vs->vtt_basename, vs->m3u8_name, vtt_basename_size); + p = strrchr(vs->vtt_basename, '.'); + if (p) + *p = '\0'; + + if ( hls->subtitle_filename ) { + strcpy(vs->vtt_m3u8_name, hls->subtitle_filename); + ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i); + if (ret < 0) + goto fail; + } else { + strcpy(vs->vtt_m3u8_name, vs->vtt_basename); + av_strlcat(vs->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size); + } + av_strlcat(vs->vtt_basename, vtt_pattern, vtt_basename_size); + } + + if (hls->baseurl) { + vs->baseurl = av_strdup(hls->baseurl); + if (!vs->baseurl) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) { + vs->fmp4_init_filename = av_strdup(vs->basename); + if (!vs->fmp4_init_filename) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + if ((ret = hls_mux_init(s, vs)) < 0) + goto fail; + + if (hls->flags & HLS_APPEND_LIST) { + parse_playlist(s, vs->m3u8_name, vs); + vs->discontinuity = 1; + if (hls->init_time > 0) { + av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time," + " hls_init_time value will have no effect\n"); + hls->init_time = 0; + hls->recording_time = hls->time * AV_TIME_BASE; + } + } + + if ((ret = hls_start(s, vs)) < 0) + goto fail; } + fail: - - av_dict_free(&options); if (ret < 0) { - av_freep(&hls->fmp4_init_filename); - av_freep(&hls->basename); - av_freep(&hls->vtt_basename); av_freep(&hls->key_basename); - if (hls->avf) - avformat_free_context(hls->avf); - if (hls->vtt_avf) - avformat_free_context(hls->vtt_avf); - + for (i = 0; i < hls->nb_varstreams && hls->var_streams; i++) { + vs = &hls->var_streams[i]; + av_freep(&vs->basename); + av_freep(&vs->vtt_basename); + av_freep(&vs->fmp4_init_filename); + av_freep(&vs->m3u8_name); + av_freep(&vs->vtt_m3u8_name); + av_freep(&vs->streams); + av_freep(&vs->agroup); + av_freep(&vs->baseurl); + if (vs->avf) + avformat_free_context(vs->avf); + if (vs->vtt_avf) + avformat_free_context(vs->vtt_avf); + } + av_freep(&hls->var_streams); + av_freep(&hls->master_m3u8_url); } - return ret; -} - -static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - HLSContext *hls = s->priv_data; - AVFormatContext *oc = NULL; - AVStream *st = s->streams[pkt->stream_index]; - int64_t end_pts = hls->recording_time * hls->number; - int is_ref_pkt = 1; - int ret = 0, can_split = 1; - int stream_index = 0; - - if (hls->sequence - hls->nb_entries > hls->start_sequence && hls->init_time > 0) { - /* reset end_pts, hls->recording_time at end of the init hls list */ - int init_list_dur = hls->init_time * hls->nb_entries * AV_TIME_BASE; - int after_init_list_dur = (hls->sequence - hls->nb_entries ) * hls->time * AV_TIME_BASE; - hls->recording_time = hls->time * AV_TIME_BASE; - end_pts = init_list_dur + after_init_list_dur ; - } - - if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) { - oc = hls->vtt_avf; - stream_index = 0; - } else { - oc = hls->avf; - stream_index = pkt->stream_index; - } - if (hls->start_pts == AV_NOPTS_VALUE) { - hls->start_pts = pkt->pts; - hls->end_pts = pkt->pts; - } - - if (hls->has_video) { - can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME)); - is_ref_pkt = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; - } - if (pkt->pts == AV_NOPTS_VALUE) - is_ref_pkt = can_split = 0; - - if (is_ref_pkt) { - if (hls->new_start) { - hls->new_start = 0; - hls->duration = (double)(pkt->pts - hls->end_pts) - * st->time_base.num / st->time_base.den; - hls->dpp = (double)(pkt->duration) * st->time_base.num / st->time_base.den; - } else { - if (pkt->duration) { - hls->duration += (double)(pkt->duration) * st->time_base.num / st->time_base.den; - } else { - av_log(s, AV_LOG_WARNING, "pkt->duration = 0, maybe the hls segment duration will not precise\n"); - hls->duration = (double)(pkt->pts - hls->end_pts) * st->time_base.num / st->time_base.den; - } - } - - } - if (hls->fmp4_init_mode || can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base, - end_pts, AV_TIME_BASE_Q) >= 0) { - int64_t new_start_pos; - char *old_filename = av_strdup(hls->avf->filename); - int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); - - if (!old_filename) { - return AVERROR(ENOMEM); - } - - av_write_frame(hls->avf, NULL); /* Flush any buffered data */ - - new_start_pos = avio_tell(hls->avf->pb); - hls->size = new_start_pos - hls->start_pos; - - if (!byterange_mode) { - ff_format_io_close(s, &oc->pb); - if (hls->vtt_avf) { - ff_format_io_close(s, &hls->vtt_avf->pb); - } - } - if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { - if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0)) - if ((hls->avf->oformat->priv_class && hls->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4) - av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0); - hls_rename_temp_file(s, oc); - } - - if (hls->fmp4_init_mode) { - hls->number--; - } - - if (!hls->fmp4_init_mode || byterange_mode) - ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); - - hls->start_pos = new_start_pos; - if (ret < 0) { - av_free(old_filename); - return ret; - } - - hls->end_pts = pkt->pts; - hls->duration = 0; - - hls->fmp4_init_mode = 0; - if (hls->flags & HLS_SINGLE_FILE) { - hls->number++; - } else if (hls->max_seg_size > 0) { - if (hls->start_pos >= hls->max_seg_size) { - hls->sequence++; - sls_flag_file_rename(hls, old_filename); - ret = hls_start(s); - hls->start_pos = 0; - /* When split segment by byte, the duration is short than hls_time, - * so it is not enough one segment duration as hls_time, */ - hls->number--; - } - hls->number++; - } else { - sls_flag_file_rename(hls, old_filename); - ret = hls_start(s); - } - av_free(old_filename); - - if (ret < 0) { - return ret; - } - - if (!hls->fmp4_init_mode || byterange_mode) - if ((ret = hls_window(s, 0)) < 0) { - return ret; - } - } - - ret = ff_write_chained(oc, stream_index, pkt, s, 0); return ret; } -static int hls_write_trailer(struct AVFormatContext *s) -{ - HLSContext *hls = s->priv_data; - AVFormatContext *oc = hls->avf; - AVFormatContext *vtt_oc = hls->vtt_avf; - char *old_filename = av_strdup(hls->avf->filename); - - if (!old_filename) { - return AVERROR(ENOMEM); - } - - - av_write_trailer(oc); - if (oc->pb) { - hls->size = avio_tell(hls->avf->pb) - hls->start_pos; - ff_format_io_close(s, &oc->pb); - - if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { - hls_rename_temp_file(s, oc); - } - - /* after av_write_trailer, then duration + 1 duration per packet */ - hls_append_segment(s, hls, hls->duration + hls->dpp, hls->start_pos, hls->size); - } - - sls_flag_file_rename(hls, old_filename); - - if (vtt_oc) { - if (vtt_oc->pb) - av_write_trailer(vtt_oc); - hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos; - ff_format_io_close(s, &vtt_oc->pb); - } - av_freep(&hls->basename); - av_freep(&hls->base_output_dirname); - av_freep(&hls->key_basename); - avformat_free_context(oc); - - hls->avf = NULL; - hls_window(s, 1); - - av_freep(&hls->fmp4_init_filename); - if (vtt_oc) { - av_freep(&hls->vtt_basename); - av_freep(&hls->vtt_m3u8_name); - avformat_free_context(vtt_oc); - } - - hls_free_segments(hls->segments); - hls_free_segments(hls->old_segments); - av_free(old_filename); - return 0; -} - #define OFFSET(x) offsetof(HLSContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -1812,6 +2523,7 @@ static const AVOption options[] = { {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX, E, "flags"}, + {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" }, @@ -1823,6 +2535,10 @@ static const AVOption options[] = { {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_FORMATTED_DATETIME }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"var_stream_map", "Variant stream map string", OFFSET(var_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"master_pl_name", "Create HLS master playlist with this name", OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, + {"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, { NULL }, }; @@ -1843,6 +2559,7 @@ AVOutputFormat ff_hls_muxer = { .video_codec = AV_CODEC_ID_H264, .subtitle_codec = AV_CODEC_ID_WEBVTT, .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .init = hls_init, .write_header = hls_write_header, .write_packet = hls_write_packet, .write_trailer = hls_write_trailer, diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c new file mode 100644 index 000000000..098dc8917 --- /dev/null +++ b/libavformat/hlsplaylist.c @@ -0,0 +1,155 @@ +/* + * Apple HTTP Live Streaming segmenter + * Copyright (c) 2012, Luca Barbato + * Copyright (c) 2017 Akamai Technologies, 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 "config.h" +#include + +#include "libavutil/time_internal.h" + +#include "avformat.h" +#include "hlsplaylist.h" + +void ff_hls_write_playlist_version(AVIOContext *out, int version) { + if (!out) + return; + avio_printf(out, "#EXTM3U\n"); + avio_printf(out, "#EXT-X-VERSION:%d\n", version); +} + +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, + char *filename, int name_id, int is_default) { + if (!out || !agroup || !filename) + return; + + avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup); + avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,URI=\"%s\"\n", name_id, + is_default ? "YES" : "NO", filename); +} + +void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, + int bandwidth, char *filename, char *agroup) { + if (!out || !filename) + return; + + if (!bandwidth) { + av_log(NULL, AV_LOG_WARNING, + "Bandwidth info not available, set audio and video bitrates\n"); + return; + } + + avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth); + if (st && st->codecpar->width > 0 && st->codecpar->height > 0) + avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width, + st->codecpar->height); + if (agroup && strlen(agroup) > 0) + avio_printf(out, ",AUDIO=\"group_%s\"", agroup); + avio_printf(out, "\n%s\n\n", filename); +} + +void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, + int target_duration, int64_t sequence, + uint32_t playlist_type) { + if (!out) + return; + ff_hls_write_playlist_version(out, version); + if (allowcache == 0 || allowcache == 1) { + avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", allowcache == 0 ? "NO" : "YES"); + } + avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); + avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + av_log(NULL, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + + if (playlist_type == PLAYLIST_TYPE_EVENT) { + avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); + } else if (playlist_type == PLAYLIST_TYPE_VOD) { + avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); + } +} + +void ff_hls_write_init_file(AVIOContext *out, char *filename, + int byterange_mode, int64_t size, int64_t pos) { + avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", filename); + if (byterange_mode) { + avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", size, pos); + } + avio_printf(out, "\n"); +} + +int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, + int byterange_mode, + double duration, int round_duration, + int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set + char *baseurl, //Ignored if NULL + char *filename, double *prog_date_time) { + if (!out || !filename) + return AVERROR(EINVAL); + + if (insert_discont) { + avio_printf(out, "#EXT-X-DISCONTINUITY\n"); + } + if (round_duration) + avio_printf(out, "#EXTINF:%ld,\n", lrint(duration)); + else + avio_printf(out, "#EXTINF:%f,\n", duration); + if (byterange_mode) + avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", size, pos); + + if (prog_date_time) { + time_t tt, wrongsecs; + int milli; + struct tm *tm, tmpbuf; + char buf0[128], buf1[128]; + tt = (int64_t)*prog_date_time; + milli = av_clip(lrint(1000*(*prog_date_time - tt)), 0, 999); + tm = localtime_r(&tt, &tmpbuf); + if (!strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm)) { + av_log(NULL, AV_LOG_DEBUG, "strftime error in ff_hls_write_file_entry\n"); + return AVERROR_UNKNOWN; + } + if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') { + int tz_min, dst = tm->tm_isdst; + tm = gmtime_r(&tt, &tmpbuf); + tm->tm_isdst = dst; + wrongsecs = mktime(tm); + tz_min = (FFABS(wrongsecs - tt) + 30) / 60; + snprintf(buf1, sizeof(buf1), + "%c%02d%02d", + wrongsecs <= tt ? '+' : '-', + tz_min / 60, + tz_min % 60); + } + avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1); + *prog_date_time += duration; + } + if (baseurl) + avio_printf(out, "%s", baseurl); + avio_printf(out, "%s\n", filename); + + return 0; +} + +void ff_hls_write_end_list (AVIOContext *out) { + if (!out) + return; + avio_printf(out, "#EXT-X-ENDLIST\n"); +} + diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h new file mode 100644 index 000000000..9969315e0 --- /dev/null +++ b/libavformat/hlsplaylist.h @@ -0,0 +1,57 @@ +/* + * Apple HTTP Live Streaming segmenter + * Copyright (c) 2012, Luca Barbato + * Copyright (c) 2017 Akamai Technologies, 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 AVFORMAT_HLSPLAYLIST_H +#define AVFORMAT_HLSPLAYLIST_H + +#include + +#include "libavutil/common.h" +#include "avformat.h" +#include "avio.h" + +typedef enum { + PLAYLIST_TYPE_NONE, + PLAYLIST_TYPE_EVENT, + PLAYLIST_TYPE_VOD, + PLAYLIST_TYPE_NB, +} PlaylistType; + +void ff_hls_write_playlist_version(AVIOContext *out, int version); +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, + char *filename, int name_id, int is_default); +void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, + int bandwidth, char *filename, char *agroup); +void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, + int target_duration, int64_t sequence, + uint32_t playlist_type); +void ff_hls_write_init_file(AVIOContext *out, char *filename, + int byterange_mode, int64_t size, int64_t pos); +int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, + int byterange_mode, + double duration, int round_duration, + int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set + char *baseurl, //Ignored if NULL + char *filename, double *prog_date_time); +void ff_hls_write_end_list (AVIOContext *out); + +#endif /* AVFORMAT_HLSPLAYLIST_H_ */ diff --git a/libavformat/http.c b/libavformat/http.c index 668cd5198..510b23375 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -66,6 +66,7 @@ typedef struct HTTPContext { int http_code; /* Used if "Transfer-Encoding: chunked" otherwise -1. */ uint64_t chunksize; + int chunkend; uint64_t off, end_off, filesize; char *location; HTTPAuthState auth_state; @@ -73,6 +74,7 @@ typedef struct HTTPContext { char *http_proxy; char *headers; char *mime_type; + char *http_version; char *user_agent; #if FF_API_HTTP_USER_AGENT char *user_agent_deprecated; @@ -115,7 +117,6 @@ typedef struct HTTPContext { int reconnect; int reconnect_at_eof; int reconnect_streamed; - int reconnect_delay; int reconnect_delay_max; int listen; char *resource; @@ -143,6 +144,7 @@ static const AVOption options[] = { { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D | E }, { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E }, { "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, + { "http_version", "export the http response version", OFFSET(http_version), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, { "cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D }, { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D }, { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT }, @@ -170,6 +172,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth, int *new_location); static int http_read_header(URLContext *h, int *new_location); +static int http_shutdown(URLContext *h, int flags); void ff_http_init_auth_state(URLContext *dest, const URLContext *src) { @@ -304,7 +307,39 @@ int ff_http_do_new_request(URLContext *h, const char *uri) HTTPContext *s = h->priv_data; AVDictionary *options = NULL; int ret; + char hostname1[1024], hostname2[1024], proto1[10], proto2[10]; + int port1, port2; + if (!h->prot || + !(!strcmp(h->prot->name, "http") || + !strcmp(h->prot->name, "https"))) + return AVERROR(EINVAL); + + av_url_split(proto1, sizeof(proto1), NULL, 0, + hostname1, sizeof(hostname1), &port1, + NULL, 0, s->location); + av_url_split(proto2, sizeof(proto2), NULL, 0, + hostname2, sizeof(hostname2), &port2, + NULL, 0, uri); + if (port1 != port2 || strncmp(hostname1, hostname2, sizeof(hostname2)) != 0) { + av_log(h, AV_LOG_ERROR, "Cannot reuse HTTP connection for different host: %s:%d != %s:%d\n", + hostname1, port1, + hostname2, port2 + ); + return AVERROR(EINVAL); + } + + if (!s->end_chunked_post) { + ret = http_shutdown(h, h->flags); + if (ret < 0) + return ret; + } + + if (s->willclose) + return AVERROR_EOF; + + s->end_chunked_post = 0; + s->chunkend = 0; s->off = 0; s->icy_data_read = 0; av_free(s->location); @@ -312,6 +347,7 @@ int ff_http_do_new_request(URLContext *h, const char *uri) if (!s->location) return AVERROR(ENOMEM); + av_log(s, AV_LOG_INFO, "Opening \'%s\' for %s\n", uri, h->flags & AVIO_FLAG_WRITE ? "writing" : "reading"); ret = http_open_cnx(h, &options); av_dict_free(&options); return ret; @@ -788,6 +824,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) } } } + av_dict_free(&new_params); // duplicate the cookie name (dict will dupe the value) if (!(eql = strchr(p, '='))) return AVERROR(EINVAL); @@ -887,6 +924,14 @@ static int process_line(URLContext *h, char *line, int line_count, } av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version); } else { + if (av_strncasecmp(p, "HTTP/1.0", 8) == 0) + s->willclose = 1; + while (*p != '/' && *p != '\0') + p++; + while (*p == '/') + p++; + av_freep(&s->http_version); + s->http_version = av_strndup(p, 3); while (!av_isspace(*p) && *p != '\0') p++; while (av_isspace(*p)) @@ -1281,6 +1326,9 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) int len; if (s->chunksize != UINT64_MAX) { + if (s->chunkend) { + return AVERROR_EOF; + } if (!s->chunksize) { char line[32]; int err; @@ -1293,11 +1341,19 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) s->chunksize = strtoull(line, NULL, 16); av_log(h, AV_LOG_TRACE, - "Chunked encoding data size: %"PRIu64"'\n", + "Chunked encoding data size: %"PRIu64"\n", s->chunksize); - if (!s->chunksize) + if (!s->chunksize && s->multiple_requests) { + http_get_line(s, line, sizeof(line)); // read empty chunk + s->chunkend = 1; return 0; + } + else if (!s->chunksize) { + av_log(h, AV_LOG_DEBUG, "Last chunk received, closing conn\n"); + ffurl_closep(&s->hd); + return 0; + } else if (s->chunksize == UINT64_MAX) { av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n", s->chunksize); @@ -1377,6 +1433,7 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) HTTPContext *s = h->priv_data; int err, new_location, read_ret; int64_t seek_ret; + int reconnect_delay = 0; if (!s->hd) return AVERROR_EOF; @@ -1392,25 +1449,29 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) return http_buf_read_compressed(h, buf, size); #endif /* CONFIG_ZLIB */ read_ret = http_buf_read(h, buf, size); - if ( (read_ret < 0 && s->reconnect && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize) - || (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) { + while ((read_ret < 0 && s->reconnect && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize) + || (read_ret == AVERROR_EOF && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) { uint64_t target = h->is_streamed ? 0 : s->off; - if (s->reconnect_delay > s->reconnect_delay_max) + if (read_ret == AVERROR_EXIT) + return read_ret; + + if (reconnect_delay > s->reconnect_delay_max) return AVERROR(EIO); - av_log(h, AV_LOG_INFO, "Will reconnect at %"PRIu64" error=%s.\n", s->off, av_err2str(read_ret)); - av_usleep(1000U*1000*s->reconnect_delay); - s->reconnect_delay = 1 + 2*s->reconnect_delay; + av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s), error=%s.\n", s->off, reconnect_delay, av_err2str(read_ret)); + err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback); + if (err != AVERROR(ETIMEDOUT)) + return err; + reconnect_delay = 1 + 2*reconnect_delay; seek_ret = http_seek_internal(h, target, SEEK_SET, 1); - if (seek_ret != target) { + if (seek_ret >= 0 && seek_ret != target) { av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target); return read_ret; } read_ret = http_buf_read(h, buf, size); - } else - s->reconnect_delay = 0; + } return read_ret; } diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c index d793807b3..b680676bf 100644 --- a/libavformat/img2enc.c +++ b/libavformat/img2enc.c @@ -42,6 +42,7 @@ typedef struct VideoMuxData { char target[4][1024]; int update; int use_strftime; + int frame_pts; const char *muxer; int use_rename; } VideoMuxData; @@ -99,12 +100,17 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n"); return AVERROR(EINVAL); } + } else if (img->frame_pts) { + if (av_get_frame_filename2(filename, sizeof(filename), img->path, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames."); + return AVERROR(EINVAL); + } } else if (av_get_frame_filename2(filename, sizeof(filename), img->path, img->img_number, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0 && img->img_number > 1) { av_log(s, AV_LOG_ERROR, - "Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n", + "Could not get frame filename number %d from pattern '%s' (either set update or use a pattern like %%03d within the filename pattern)\n", img->img_number, img->path); return AVERROR(EINVAL); } @@ -203,10 +209,10 @@ static int query_codec(enum AVCodecID id, int std_compliance) #define OFFSET(x) offsetof(VideoMuxData, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption muxoptions[] = { - { "updatefirst", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC }, { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, + { "frame_pts", "use current frame pts for filename", OFFSET(frame_pts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "atomic_writing", "write files atomically (using temporary files and renames)", OFFSET(use_rename), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { NULL }, }; diff --git a/libavformat/internal.h b/libavformat/internal.h index d136c79bd..0cd0556dc 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -120,12 +120,6 @@ struct AVFormatInternal { int avoid_negative_ts_use_pts; - /** - * Whether or not a header has already been written - */ - int header_written; - int write_header_ret; - /** * Timestamp of the end of the shortest stream. */ @@ -196,6 +190,8 @@ struct AVStreamInternal { * Whether the internal avctx needs to be updated from codecpar (after a late change to codecpar) */ int need_context_update; + + FFFrac *priv_pts; }; #ifdef __GNUC__ @@ -545,8 +541,11 @@ static inline int ff_rename(const char *oldpath, const char *newpath, void *logc int ret = 0; if (rename(oldpath, newpath) == -1) { ret = AVERROR(errno); - if (logctx) - av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s\n", oldpath, newpath); + if (logctx) { + char err[AV_ERROR_MAX_STRING_SIZE] = {0}; + av_make_error_string(err, AV_ERROR_MAX_STRING_SIZE, ret); + av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s: %s\n", oldpath, newpath, err); + } } return ret; } @@ -622,6 +621,14 @@ int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **op */ void ff_format_io_close(AVFormatContext *s, AVIOContext **pb); +/** + * Utility function to check if the file uses http or https protocol + * + * @param s AVFormatContext + * @param filename URL or file name to open for writing + */ +int ff_is_http_proto(char *filename); + /** * Parse creation_time in AVFormatContext metadata if exists and warn if the * parsing fails. @@ -685,4 +692,8 @@ int ff_bprint_to_codecpar_extradata(AVCodecParameters *par, struct AVBPrint *buf int ff_interleaved_peek(AVFormatContext *s, int stream, AVPacket *pkt, int add_offset); + +int ff_lock_avformat(void); +int ff_unlock_avformat(void); + #endif /* AVFORMAT_INTERNAL_H */ diff --git a/libavformat/isom.c b/libavformat/isom.c index 77983c5ea..9d9f85885 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -524,7 +524,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (tag == MP4DecSpecificDescrTag) { av_log(fc, AV_LOG_TRACE, "Specific MPEG-4 header len=%d\n", len); if (!len || (uint64_t)len > (1<<30)) - return -1; + return AVERROR_INVALIDDATA; av_free(st->codecpar->extradata); if ((ret = ff_get_extradata(fc, st->codecpar, pb, len)) < 0) return ret; diff --git a/libavformat/isom.h b/libavformat/isom.h index b9380e9dc..65676fb0f 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -93,7 +93,6 @@ typedef struct MOVFragment { unsigned duration; unsigned size; unsigned flags; - int64_t time; } MOVFragment; typedef struct MOVTrackExt { @@ -109,17 +108,28 @@ typedef struct MOVSbgp { unsigned int index; } MOVSbgp; +typedef struct MOVFragmentStreamInfo { + int id; + int64_t sidx_pts; + int64_t first_tfra_pts; + int64_t tfdt_dts; + int index_entry; +} MOVFragmentStreamInfo; + typedef struct MOVFragmentIndexItem { int64_t moof_offset; - int64_t time; int headers_read; + int current; + int nb_stream_info; + MOVFragmentStreamInfo * stream_info; } MOVFragmentIndexItem; typedef struct MOVFragmentIndex { - unsigned track_id; - unsigned item_count; - unsigned current_item; - MOVFragmentIndexItem *items; + int allocated_size; + int complete; + int current; + int nb_items; + MOVFragmentIndexItem * item; } MOVFragmentIndex; typedef struct MOVIndexRange { @@ -250,9 +260,7 @@ typedef struct MOVContext { int moov_retry; int use_mfra_for; int has_looked_for_mfra; - MOVFragmentIndex** fragment_index_data; - unsigned fragment_index_count; - int fragment_index_complete; + MOVFragmentIndex frag_index; int atom_depth; unsigned int aax_mode; ///< 'aax' file has been detected uint8_t file_key[20]; @@ -310,6 +318,11 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); #define MOV_TKHD_FLAG_IN_PREVIEW 0x0004 #define MOV_TKHD_FLAG_IN_POSTER 0x0008 +#define MOV_SAMPLE_DEPENDENCY_UNKNOWN 0x0 +#define MOV_SAMPLE_DEPENDENCY_YES 0x1 +#define MOV_SAMPLE_DEPENDENCY_NO 0x2 + + #define TAG_IS_AVCI(tag) \ ((tag) == MKTAG('a', 'i', '5', 'p') || \ (tag) == MKTAG('a', 'i', '5', 'q') || \ @@ -328,7 +341,6 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb); -enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags); int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries); void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout); @@ -337,4 +349,18 @@ void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout); #define FF_MOV_FLAG_MFRA_DTS 1 #define FF_MOV_FLAG_MFRA_PTS 2 +/** + * Compute codec id for 'lpcm' tag. + * See CoreAudioTypes and AudioStreamBasicDescription at Apple. + */ +static inline enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags) +{ + /* lpcm flags: + * 0x1 = float + * 0x2 = big-endian + * 0x4 = signed + */ + return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0); +} + #endif /* AVFORMAT_ISOM_H */ diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c index fdc0ee03e..f591327a2 100644 --- a/libavformat/ivfenc.c +++ b/libavformat/ivfenc.c @@ -37,14 +37,17 @@ static int ivf_write_header(AVFormatContext *s) } par = s->streams[0]->codecpar; if (par->codec_type != AVMEDIA_TYPE_VIDEO || - !(par->codec_id == AV_CODEC_ID_VP8 || par->codec_id == AV_CODEC_ID_VP9)) { - av_log(s, AV_LOG_ERROR, "Currently only VP8 and VP9 are supported!\n"); + !(par->codec_id == AV_CODEC_ID_VP8 || par->codec_id == AV_CODEC_ID_VP9 || + par->codec_id == AV_CODEC_ID_AV1)) { + av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are supported!\n"); return AVERROR(EINVAL); } avio_write(pb, "DKIF", 4); avio_wl16(pb, 0); // version avio_wl16(pb, 32); // header length - avio_wl32(pb, par->codec_tag ? par->codec_tag : par->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") : AV_RL32("VP80")); + avio_wl32(pb, par->codec_tag ? par->codec_tag : + par->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") : + par->codec_id == AV_CODEC_ID_VP8 ? AV_RL32("VP80") : AV_RL32("AV01")); avio_wl16(pb, par->width); avio_wl16(pb, par->height); avio_wl32(pb, s->streams[0]->time_base.den); @@ -100,6 +103,7 @@ static int ivf_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) static const AVCodecTag codec_ivf_tags[] = { { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, + { AV_CODEC_ID_AV1, MKTAG('A', 'V', '0', '1') }, { AV_CODEC_ID_NONE, 0 } }; diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c index c919976d4..273197bb5 100644 --- a/libavformat/latmenc.c +++ b/libavformat/latmenc.c @@ -128,7 +128,7 @@ static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs) int ret = init_get_bits8(&gb, par->extradata, par->extradata_size); av_assert0(ret >= 0); // extradata size has been checked already, so this should not fail skip_bits_long(&gb, ctx->off + 3); - avpriv_copy_pce_data(bs, &gb); + ff_copy_pce_data(bs, &gb); } } diff --git a/libavformat/libavformat.v b/libavformat/libavformat.v index c961cd8f1..47d5ddcdb 100644 --- a/libavformat/libavformat.v +++ b/libavformat/libavformat.v @@ -1,19 +1,6 @@ LIBAVFORMAT_MAJOR { global: av*; - #FIXME those are for ffserver - ff_inet_aton; - ff_socket_nonblock; - ff_rtsp_parse_line; - ff_rtp_get_local_rtp_port; - ff_rtp_get_local_rtcp_port; - ffio_open_dyn_packet_buf; - ffio_set_buf_size; - ffurl_close; - ffurl_open; - ffurl_write; - #those are deprecated, remove on next bump - url_feof; local: *; }; diff --git a/libavformat/libopenmpt.c b/libavformat/libopenmpt.c index af6eb1ac4..30c3d6e64 100644 --- a/libavformat/libopenmpt.c +++ b/libavformat/libopenmpt.c @@ -21,6 +21,14 @@ #include #include +#include +/* Shims to support libopenmpt < 0.3.0 (as documented by libopenmpt) */ +#if !defined(OPENMPT_API_VERSION_MAKE) +#define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0)) +#endif +#if !defined(OPENMPT_API_VERSION_AT_LEAST) +#define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) +#endif #include "libavutil/avstring.h" #include "libavutil/opt.h" @@ -72,13 +80,17 @@ static int read_header_openmpt(AVFormatContext *s) { AVStream *st; OpenMPTContext *openmpt = s->priv_data; - int64_t size = avio_size(s->pb); - if (size <= 0) - return AVERROR_INVALIDDATA; - char *buf = av_malloc(size); + int64_t size; + char *buf; +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0) + int error; +#endif int ret; - + size = avio_size(s->pb); + if (size <= 0) + return AVERROR_INVALIDDATA; + buf = av_malloc(size); if (!buf) return AVERROR(ENOMEM); size = avio_read(s->pb, buf, size); @@ -88,10 +100,24 @@ static int read_header_openmpt(AVFormatContext *s) return size; } +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0) + error = OPENMPT_ERROR_OK; + openmpt->module = openmpt_module_create_from_memory2(buf, size, openmpt_logfunc, s, NULL, NULL, &error, NULL, NULL); + av_freep(&buf); + if (!openmpt->module) { + if (error == OPENMPT_ERROR_OUT_OF_MEMORY) + return AVERROR(ENOMEM); + else if (error >= OPENMPT_ERROR_GENERAL) + return AVERROR_INVALIDDATA; + else + return AVERROR_UNKNOWN; + } +#else openmpt->module = openmpt_module_create_from_memory(buf, size, openmpt_logfunc, s, NULL); av_freep(&buf); if (!openmpt->module) return AVERROR_INVALIDDATA; +#endif openmpt->channels = av_get_channel_layout_nb_channels(openmpt->layout); diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 94a56ebfa..496499b55 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1989,18 +1989,25 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) return AVERROR_INVALIDDATA; } break; + case MATROSKA_VIDEO_PROJECTION_TYPE_RECTANGULAR: + /* No Spherical metadata */ + return 0; default: + av_log(NULL, AV_LOG_WARNING, + "Unknown spherical metadata type %"PRIu64"\n", + track->video.projection.type); return 0; } spherical = av_spherical_alloc(&spherical_size); if (!spherical) return AVERROR(ENOMEM); + spherical->projection = projection; - spherical->yaw = (int32_t)(track->video.projection.yaw * (1 << 16)); - spherical->pitch = (int32_t)(track->video.projection.pitch * (1 << 16)); - spherical->roll = (int32_t)(track->video.projection.roll * (1 << 16)); + spherical->yaw = (int32_t) (track->video.projection.yaw * (1 << 16)); + spherical->pitch = (int32_t) (track->video.projection.pitch * (1 << 16)); + spherical->roll = (int32_t) (track->video.projection.roll * (1 << 16)); spherical->padding = padding; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 6f094c458..f22c2ab70 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -953,78 +953,79 @@ static int mkv_write_video_color(AVIOContext *pb, AVCodecParameters *par, AVStre return 0; } -static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, AVStream *st) +static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, + AVStream *st) { + AVIOContext b; + AVIOContext *dyn_cp; int side_data_size = 0; + int ret, projection_size; + uint8_t *projection_ptr; + uint8_t private[20]; + const AVSphericalMapping *spherical = - (const AVSphericalMapping*) av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, + (const AVSphericalMapping *)av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, &side_data_size); - if (side_data_size) { - AVIOContext *dyn_cp; - uint8_t *projection_ptr; - int ret, projection_size; + if (!side_data_size) + return 0; - ret = avio_open_dyn_buf(&dyn_cp); - if (ret < 0) - return ret; + ret = avio_open_dyn_buf(&dyn_cp); + if (ret < 0) + return ret; - switch (spherical->projection) { - case AV_SPHERICAL_EQUIRECTANGULAR: - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, - MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); - break; - case AV_SPHERICAL_EQUIRECTANGULAR_TILE: - { - AVIOContext b; - uint8_t private[20]; - ffio_init_context(&b, private, sizeof(private), - 1, NULL, NULL, NULL, NULL); - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, - MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); - avio_wb32(&b, 0); // version + flags - avio_wb32(&b, spherical->bound_top); - avio_wb32(&b, spherical->bound_bottom); - avio_wb32(&b, spherical->bound_left); - avio_wb32(&b, spherical->bound_right); - put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, private, sizeof(private)); - break; - } - case AV_SPHERICAL_CUBEMAP: - { - AVIOContext b; - uint8_t private[12]; - ffio_init_context(&b, private, sizeof(private), - 1, NULL, NULL, NULL, NULL); - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, - MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP); - avio_wb32(&b, 0); // version + flags - avio_wb32(&b, 0); // layout - avio_wb32(&b, spherical->padding); - put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, private, sizeof(private)); - break; - } - default: - av_log(s, AV_LOG_WARNING, "Unknown projection type\n"); - goto end; - } + switch (spherical->projection) { + case AV_SPHERICAL_EQUIRECTANGULAR: + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, + MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); + break; + case AV_SPHERICAL_EQUIRECTANGULAR_TILE: + ffio_init_context(&b, private, 20, 1, NULL, NULL, NULL, NULL); + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, + MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); + avio_wb32(&b, 0); // version + flags + avio_wb32(&b, spherical->bound_top); + avio_wb32(&b, spherical->bound_bottom); + avio_wb32(&b, spherical->bound_left); + avio_wb32(&b, spherical->bound_right); + put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, + private, avio_tell(&b)); + break; + case AV_SPHERICAL_CUBEMAP: + ffio_init_context(&b, private, 12, 1, NULL, NULL, NULL, NULL); + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, + MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP); + avio_wb32(&b, 0); // version + flags + avio_wb32(&b, 0); // layout + avio_wb32(&b, spherical->padding); + put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, + private, avio_tell(&b)); + break; + default: + av_log(s, AV_LOG_WARNING, "Unknown projection type\n"); + goto end; + } - if (spherical->yaw) - put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, (double)spherical->yaw / (1 << 16)); - if (spherical->pitch) - put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, (double)spherical->pitch / (1 << 16)); - if (spherical->roll) - put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, (double)spherical->roll / (1 << 16)); + if (spherical->yaw) + put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, + (double) spherical->yaw / (1 << 16)); + if (spherical->pitch) + put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, + (double) spherical->pitch / (1 << 16)); + if (spherical->roll) + put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, + (double) spherical->roll / (1 << 16)); end: - projection_size = avio_close_dyn_buf(dyn_cp, &projection_ptr); - if (projection_size) { - ebml_master projection = start_ebml_master(pb, MATROSKA_ID_VIDEOPROJECTION, projection_size); - avio_write(pb, projection_ptr, projection_size); - end_ebml_master(pb, projection); - } - av_freep(&projection_ptr); + projection_size = avio_close_dyn_buf(dyn_cp, &projection_ptr); + if (projection_size) { + ebml_master projection = start_ebml_master(pb, + MATROSKA_ID_VIDEOPROJECTION, + projection_size); + avio_write(pb, projection_ptr, projection_size); + end_ebml_master(pb, projection); } + av_freep(&projection_ptr); return 0; } @@ -1859,17 +1860,6 @@ static int mkv_write_header(AVFormatContext *s) version = 4; for (i = 0; i < s->nb_streams; i++) { - if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_ATRAC3 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_COOK || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RA_288 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_SIPR || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV10 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV20) { - av_log(s, AV_LOG_ERROR, - "The Matroska muxer does not yet support muxing %s\n", - avcodec_get_name(s->streams[i]->codecpar->codec_id)); - return AVERROR_PATCHWELCOME; - } if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS || av_dict_get(s->streams[i]->metadata, "stereo_mode", NULL, 0) || av_dict_get(s->streams[i]->metadata, "alpha_mode", NULL, 0)) @@ -1975,6 +1965,10 @@ static int mkv_write_header(AVFormatContext *s) // initialize stream_duration fields mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t)); + if (!mkv->stream_durations || !mkv->stream_duration_offsets) { + ret = AVERROR(ENOMEM); + goto fail; + } ret = mkv_write_tracks(s); if (ret < 0) @@ -2648,6 +2642,27 @@ static int mkv_init(struct AVFormatContext *s) { int i; + if (s->nb_streams > MAX_TRACKS) { + av_log(s, AV_LOG_ERROR, + "At most %d streams are supported for muxing in Matroska\n", + MAX_TRACKS); + return AVERROR(EINVAL); + } + + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_ATRAC3 || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_COOK || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RA_288 || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_SIPR || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV10 || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV20) { + av_log(s, AV_LOG_ERROR, + "The Matroska muxer does not yet support muxing %s\n", + avcodec_get_name(s->streams[i]->codecpar->codec_id)); + return AVERROR_PATCHWELCOME; + } + } + if (s->avoid_negative_ts < 0) { s->avoid_negative_ts = 1; s->internal->avoid_negative_ts_use_pts = 1; diff --git a/libavformat/mov.c b/libavformat/mov.c index 899690d92..22faecfc1 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -767,28 +767,6 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb) -{ - AVStream *st; - int tag; - - if (fc->nb_streams < 1) - return 0; - st = fc->streams[fc->nb_streams-1]; - - avio_rb32(pb); /* version + flags */ - ff_mp4_read_descr(fc, pb, &tag); - if (tag == MP4ESDescrTag) { - ff_mp4_parse_es_descr(pb, NULL); - } else - avio_rb16(pb); /* ID */ - - ff_mp4_read_descr(fc, pb, &tag); - if (tag == MP4DecConfigDescrTag) - ff_mp4_read_dec_config_descr(fc, st, pb); - return 0; -} - static int mov_read_esds(MOVContext *c, AVIOContext *pb, MOVAtom atom) { return ff_mov_read_esds(c->fc, pb); @@ -1168,6 +1146,216 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; /* now go for mdat */ } +static MOVFragmentStreamInfo * get_frag_stream_info( + MOVFragmentIndex *frag_index, + int index, + int id) +{ + int i; + MOVFragmentIndexItem * item; + + if (index < 0 || index >= frag_index->nb_items) + return NULL; + item = &frag_index->item[index]; + for (i = 0; i < item->nb_stream_info; i++) + if (item->stream_info[i].id == id) + return &item->stream_info[i]; + + // This shouldn't happen + return NULL; +} + +static void set_frag_stream(MOVFragmentIndex *frag_index, int id) +{ + int i; + MOVFragmentIndexItem * item; + + if (frag_index->current < 0 || + frag_index->current >= frag_index->nb_items) + return; + + item = &frag_index->item[frag_index->current]; + for (i = 0; i < item->nb_stream_info; i++) + if (item->stream_info[i].id == id) { + item->current = i; + return; + } + + // id not found. This shouldn't happen. + item->current = -1; +} + +static MOVFragmentStreamInfo * get_current_frag_stream_info( + MOVFragmentIndex *frag_index) +{ + MOVFragmentIndexItem *item; + if (frag_index->current < 0 || + frag_index->current >= frag_index->nb_items) + return NULL; + + item = &frag_index->item[frag_index->current]; + if (item->current >= 0 && item->current < item->nb_stream_info) + return &item->stream_info[item->current]; + + // This shouldn't happen + return NULL; +} + +static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset) +{ + int a, b, m; + int64_t moof_offset; + + // Optimize for appending new entries + if (!frag_index->nb_items || + frag_index->item[frag_index->nb_items - 1].moof_offset < offset) + return frag_index->nb_items; + + a = -1; + b = frag_index->nb_items; + + while (b - a > 1) { + m = (a + b) >> 1; + moof_offset = frag_index->item[m].moof_offset; + if (moof_offset >= offset) + b = m; + if (moof_offset <= offset) + a = m; + } + return b; +} + +static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info) +{ + + if (frag_stream_info) { + if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) + return frag_stream_info->sidx_pts; + if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) + return frag_stream_info->first_tfra_pts; + if (frag_stream_info->tfdt_dts != AV_NOPTS_VALUE) + return frag_stream_info->tfdt_dts; + } + return AV_NOPTS_VALUE; +} + +static int64_t get_frag_time(MOVFragmentIndex *frag_index, + int index, int track_id) +{ + MOVFragmentStreamInfo * frag_stream_info; + int64_t timestamp; + int i; + + if (track_id >= 0) { + frag_stream_info = get_frag_stream_info(frag_index, index, track_id); + return frag_stream_info->sidx_pts; + } + + for (i = 0; i < frag_index->item[index].nb_stream_info; i++) { + frag_stream_info = &frag_index->item[index].stream_info[i]; + timestamp = get_stream_info_time(frag_stream_info); + if (timestamp != AV_NOPTS_VALUE) + return timestamp; + } + return AV_NOPTS_VALUE; +} + +static int search_frag_timestamp(MOVFragmentIndex *frag_index, + AVStream *st, int64_t timestamp) +{ + int a, b, m; + int64_t frag_time; + int id = -1; + + if (st) { + // If the stream is referenced by any sidx, limit the search + // to fragments that referenced this stream in the sidx + MOVStreamContext *sc = st->priv_data; + if (sc->has_sidx) + id = st->id; + } + + a = -1; + b = frag_index->nb_items; + + while (b - a > 1) { + m = (a + b) >> 1; + frag_time = get_frag_time(frag_index, m, id); + if (frag_time != AV_NOPTS_VALUE) { + if (frag_time >= timestamp) + b = m; + if (frag_time <= timestamp) + a = m; + } + } + return a; +} + +static int update_frag_index(MOVContext *c, int64_t offset) +{ + int index, i; + MOVFragmentIndexItem * item; + MOVFragmentStreamInfo * frag_stream_info; + + // If moof_offset already exists in frag_index, return index to it + index = search_frag_moof_offset(&c->frag_index, offset); + if (index < c->frag_index.nb_items && + c->frag_index.item[index].moof_offset == offset) + return index; + + // offset is not yet in frag index. + // Insert new item at index (sorted by moof offset) + item = av_fast_realloc(c->frag_index.item, + &c->frag_index.allocated_size, + (c->frag_index.nb_items + 1) * + sizeof(*c->frag_index.item)); + if(!item) + return -1; + c->frag_index.item = item; + + frag_stream_info = av_realloc_array(NULL, c->fc->nb_streams, + sizeof(*item->stream_info)); + if (!frag_stream_info) + return -1; + + for (i = 0; i < c->fc->nb_streams; i++) { + frag_stream_info[i].id = c->fc->streams[i]->id; + frag_stream_info[i].sidx_pts = AV_NOPTS_VALUE; + frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE; + frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE; + frag_stream_info[i].index_entry = -1; + } + + if (index < c->frag_index.nb_items) + memmove(c->frag_index.item + index + 1, c->frag_index.item + index, + (c->frag_index.nb_items - index) * sizeof(*c->frag_index.item)); + + item = &c->frag_index.item[index]; + item->headers_read = 0; + item->current = 0; + item->nb_stream_info = c->fc->nb_streams; + item->moof_offset = offset; + item->stream_info = frag_stream_info; + c->frag_index.nb_items++; + + return index; +} + +static void fix_frag_index_entries(MOVFragmentIndex *frag_index, int index, + int id, int entries) +{ + int i; + MOVFragmentStreamInfo * frag_stream_info; + + if (index < 0) + return; + for (i = index; i < frag_index->nb_items; i++) { + frag_stream_info = get_frag_stream_info(frag_index, i, id); + if (frag_stream_info && frag_stream_info->index_entry >= 0) + frag_stream_info->index_entry += entries; + } +} + static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) { if (!c->has_looked_for_mfra && c->use_mfra_for > 0) { @@ -1187,6 +1375,7 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) } c->fragment.moof_offset = c->fragment.implicit_offset = avio_tell(pb) - 8; av_log(c->fc, AV_LOG_TRACE, "moof offset %"PRIx64"\n", c->fragment.moof_offset); + c->frag_index.current = update_frag_index(c, c->fragment.moof_offset); return mov_read_default(c, pb, atom); } @@ -1544,6 +1733,7 @@ static int mov_read_ares(MOVContext *c, AVIOContext *pb, MOVAtom atom) par->width = 1440; return 0; } else if ((par->codec_tag == MKTAG('A', 'V', 'd', '1') || + par->codec_tag == MKTAG('A', 'V', 'j', '2') || par->codec_tag == MKTAG('A', 'V', 'd', 'n')) && atom.size >= 24) { int num, den; @@ -1801,26 +1991,14 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->chunk_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STCO atom\n"); return AVERROR_EOF; + } return 0; } -/** - * Compute codec id for 'lpcm' tag. - * See CoreAudioTypes and AudioStreamBasicDescription at Apple. - */ -enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags) -{ - /* lpcm flags: - * 0x1 = float - * 0x2 = big-endian - * 0x4 = signed - */ - return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0); -} - static int mov_codec_id(AVStream *st, uint32_t format) { int id = ff_codec_get_id(ff_codec_movaudio_tags, format); @@ -2262,8 +2440,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) MOVStreamContext *sc; int pseudo_stream_id; - if (c->fc->nb_streams < 1) - return 0; + av_assert0 (c->fc->nb_streams >= 1); st = c->fc->streams[c->fc->nb_streams-1]; sc = st->priv_data; @@ -2289,8 +2466,10 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) } if (mov_skip_multiple_stsd(c, pb, st->codecpar->codec_tag, format, - size - (avio_tell(pb) - start_pos))) + size - (avio_tell(pb) - start_pos))) { + sc->stsd_count++; continue; + } sc->pseudo_stream_id = st->codecpar->codec_tag ? -1 : pseudo_stream_id; sc->dref_id= dref_id; @@ -2342,10 +2521,13 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) av_freep(&st->codecpar->extradata); st->codecpar->extradata_size = 0; } + sc->stsd_count++; } - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSD atom\n"); return AVERROR_EOF; + } return 0; } @@ -2378,17 +2560,18 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) /* Prepare space for hosting multiple extradata. */ sc->extradata = av_mallocz_array(entries, sizeof(*sc->extradata)); + if (!sc->extradata) + return AVERROR(ENOMEM); + sc->extradata_size = av_mallocz_array(entries, sizeof(*sc->extradata_size)); - if (!sc->extradata_size || !sc->extradata) { + if (!sc->extradata_size) { ret = AVERROR(ENOMEM); goto fail; } ret = ff_mov_read_stsd_entries(c, pb, entries); if (ret < 0) - return ret; - - sc->stsd_count = entries; + goto fail; /* Restore back the primary extradata. */ av_freep(&st->codecpar->extradata); @@ -2422,6 +2605,8 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb24(pb); /* flags */ entries = avio_rb32(pb); + if ((uint64_t)entries * 12 + 4 > atom.size) + return AVERROR_INVALIDDATA; av_log(c->fc, AV_LOG_TRACE, "track[%u].stsc.entries = %u\n", c->fc->nb_streams - 1, entries); @@ -2443,8 +2628,10 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stsc_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSC atom\n"); return AVERROR_EOF; + } return 0; } @@ -2495,8 +2682,10 @@ static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stps_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STPS atom\n"); return AVERROR_EOF; + } return 0; } @@ -2542,8 +2731,10 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->keyframe_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSS atom\n"); return AVERROR_EOF; + } return 0; } @@ -2627,8 +2818,10 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_free(buf); - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSZ atom\n"); return AVERROR_EOF; + } return 0; } @@ -2637,7 +2830,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - unsigned int i, entries; + unsigned int i, entries, alloc_size = 0; int64_t duration=0; int64_t total_sample_count=0; @@ -2655,15 +2848,24 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (sc->stts_data) av_log(c->fc, AV_LOG_WARNING, "Duplicated STTS atom\n"); - av_free(sc->stts_data); + av_freep(&sc->stts_data); sc->stts_count = 0; - sc->stts_data = av_malloc_array(entries, sizeof(*sc->stts_data)); - if (!sc->stts_data) + if (entries >= INT_MAX / sizeof(*sc->stts_data)) return AVERROR(ENOMEM); for (i = 0; i < entries && !pb->eof_reached; i++) { int sample_duration; unsigned int sample_count; + unsigned min_entries = FFMIN(FFMAX(i, 1024 * 1024), entries); + MOVStts *stts_data = av_fast_realloc(sc->stts_data, &alloc_size, + min_entries * sizeof(*sc->stts_data)); + if (!stts_data) { + av_freep(&sc->stts_data); + sc->stts_count = 0; + return AVERROR(ENOMEM); + } + sc->stts_count = min_entries; + sc->stts_data = stts_data; sample_count=avio_rb32(pb); sample_duration = avio_rb32(pb); @@ -2689,8 +2891,10 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->duration_for_fps += duration; sc->nb_frames_for_fps += total_sample_count; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STTS atom\n"); return AVERROR_EOF; + } st->nb_frames= total_sample_count; if (duration) @@ -2714,7 +2918,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - unsigned int i, j, entries, ctts_count = 0; + unsigned int i, entries, ctts_count = 0; if (c->fc->nb_streams < 1) return 0; @@ -2747,9 +2951,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) continue; } - /* Expand entries such that we have a 1-1 mapping with samples. */ - for (j = 0; j < count; j++) - add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size, 1, duration); + add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size, + count, duration); av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n", count, duration); @@ -2767,8 +2970,10 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->ctts_count = ctts_count; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted CTTS atom\n"); return AVERROR_EOF; + } av_log(c->fc, AV_LOG_TRACE, "dts shift %d\n", sc->dts_shift); @@ -2814,7 +3019,12 @@ static int mov_read_sbgp(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->rap_group_count = i; - return pb->eof_reached ? AVERROR_EOF : 0; + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted SBGP atom\n"); + return AVERROR_EOF; + } + + return 0; } /** @@ -2844,34 +3054,99 @@ static int get_edit_list_entry(MOVContext *mov, } /** - * Find the closest previous frame to the timestamp, in e_old index + * Find the closest previous frame to the timestamp_pts, in e_old index * entries. Searching for just any frame / just key frames can be controlled by * last argument 'flag'. - * Returns the index of the entry in st->index_entries if successful, - * else returns -1. + * Note that if ctts_data is not NULL, we will always search for a key frame + * irrespective of the value of 'flag'. If we don't find any keyframe, we will + * return the first frame of the video. + * + * Here the timestamp_pts is considered to be a presentation timestamp and + * the timestamp of index entries are considered to be decoding timestamps. + * + * Returns 0 if successful in finding a frame, else returns -1. + * Places the found index corresponding output arg. + * + * If ctts_old is not NULL, then refines the searched entry by searching + * backwards from the found timestamp, to find the frame with correct PTS. + * + * Places the found ctts_index and ctts_sample in corresponding output args. */ -static int64_t find_prev_closest_index(AVStream *st, - AVIndexEntry *e_old, - int nb_old, - int64_t timestamp, - int flag) +static int find_prev_closest_index(AVStream *st, + AVIndexEntry *e_old, + int nb_old, + MOVStts* ctts_data, + int64_t ctts_count, + int64_t timestamp_pts, + int flag, + int64_t* index, + int64_t* ctts_index, + int64_t* ctts_sample) { + MOVStreamContext *msc = st->priv_data; AVIndexEntry *e_keep = st->index_entries; int nb_keep = st->nb_index_entries; - int64_t found = -1; int64_t i = 0; + int64_t index_ctts_count; + + av_assert0(index); + + // If dts_shift > 0, then all the index timestamps will have to be offset by + // at least dts_shift amount to obtain PTS. + // Hence we decrement the searched timestamp_pts by dts_shift to find the closest index element. + if (msc->dts_shift > 0) { + timestamp_pts -= msc->dts_shift; + } st->index_entries = e_old; st->nb_index_entries = nb_old; - found = av_index_search_timestamp(st, timestamp, flag | AVSEEK_FLAG_BACKWARD); + *index = av_index_search_timestamp(st, timestamp_pts, flag | AVSEEK_FLAG_BACKWARD); // Keep going backwards in the index entries until the timestamp is the same. - if (found >= 0) { - for (i = found; i > 0 && e_old[i].timestamp == e_old[i - 1].timestamp; + if (*index >= 0) { + for (i = *index; i > 0 && e_old[i].timestamp == e_old[i - 1].timestamp; i--) { if ((flag & AVSEEK_FLAG_ANY) || (e_old[i - 1].flags & AVINDEX_KEYFRAME)) { - found = i - 1; + *index = i - 1; + } + } + } + + // If we have CTTS then refine the search, by searching backwards over PTS + // computed by adding corresponding CTTS durations to index timestamps. + if (ctts_data && *index >= 0) { + av_assert0(ctts_index); + av_assert0(ctts_sample); + // Find out the ctts_index for the found frame. + *ctts_index = 0; + *ctts_sample = 0; + for (index_ctts_count = 0; index_ctts_count < *index; index_ctts_count++) { + if (*ctts_index < ctts_count) { + (*ctts_sample)++; + if (ctts_data[*ctts_index].count == *ctts_sample) { + (*ctts_index)++; + *ctts_sample = 0; + } + } + } + + while (*index >= 0 && (*ctts_index) >= 0) { + // Find a "key frame" with PTS <= timestamp_pts (So that we can decode B-frames correctly). + // No need to add dts_shift to the timestamp here becase timestamp_pts has already been + // compensated by dts_shift above. + if ((e_old[*index].timestamp + ctts_data[*ctts_index].duration) <= timestamp_pts && + (e_old[*index].flags & AVINDEX_KEYFRAME)) { + break; + } + + (*index)--; + if (*ctts_sample == 0) { + (*ctts_index)--; + if (*ctts_index >= 0) + *ctts_sample = ctts_data[*ctts_index].count - 1; + } else { + (*ctts_sample)--; } } } @@ -2879,7 +3154,7 @@ static int64_t find_prev_closest_index(AVStream *st, /* restore AVStream state*/ st->index_entries = e_keep; st->nb_index_entries = nb_keep; - return found; + return *index >= 0 ? 0 : -1; } /** @@ -2975,6 +3250,60 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns return *ctts_count; } +#define MAX_REORDER_DELAY 16 +static void mov_estimate_video_delay(MOVContext *c, AVStream* st) { + MOVStreamContext *msc = st->priv_data; + int ind; + int ctts_ind = 0; + int ctts_sample = 0; + int64_t pts_buf[MAX_REORDER_DELAY + 1]; // Circular buffer to sort pts. + int buf_start = 0; + int buf_size = 0; + int j, r, num_swaps; + + if (st->codecpar->video_delay <= 0 && msc->ctts_data && + st->codecpar->codec_id == AV_CODEC_ID_H264) { + st->codecpar->video_delay = 0; + for(ind = 0; ind < st->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { + if (buf_size == (MAX_REORDER_DELAY + 1)) { + // If circular buffer is full, then move the first element forward. + buf_start = (buf_start + 1) % buf_size; + } else { + ++buf_size; + } + + // Point j to the last elem of the buffer and insert the current pts there. + j = (buf_start + buf_size - 1) % buf_size; + pts_buf[j] = st->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration; + + // The timestamps that are already in the sorted buffer, and are greater than the + // current pts, are exactly the timestamps that need to be buffered to output PTS + // in correct sorted order. + // Hence the video delay (which is the buffer size used to sort DTS and output PTS), + // can be computed as the maximum no. of swaps any particular timestamp needs to + // go through, to keep this buffer in sorted order. + num_swaps = 0; + while (j != buf_start) { + r = (j - 1 + buf_size) % buf_size; + if (pts_buf[j] < pts_buf[r]) { + FFSWAP(int64_t, pts_buf[j], pts_buf[r]); + ++num_swaps; + } + j = r; + } + st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, num_swaps); + + ctts_sample++; + if (ctts_sample == msc->ctts_data[ctts_ind].count) { + ctts_ind++; + ctts_sample = 0; + } + } + av_log(c->fc, AV_LOG_DEBUG, "Setting codecpar->delay to %d for stream st: %d\n", + st->codecpar->video_delay, st->index); + } +} + static void mov_current_sample_inc(MOVStreamContext *sc) { sc->current_sample++; @@ -3050,10 +3379,8 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) int64_t empty_edits_sum_duration = 0; int64_t edit_list_index = 0; int64_t index; - int64_t index_ctts_count; int flags; int64_t start_dts = 0; - int64_t edit_list_media_time_dts = 0; int64_t edit_list_start_encountered = 0; int64_t search_timestamp = 0; int64_t* frame_duration_buffer = NULL; @@ -3062,6 +3389,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) int packet_skip_samples = 0; MOVIndexRange *current_index_range; int i; + int found_keyframe_after_edit = 0; if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) { return; @@ -3123,17 +3451,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) st->skip_samples = msc->start_pad = 0; } - //find closest previous key frame - edit_list_media_time_dts = edit_list_media_time; - if (msc->dts_shift > 0) { - edit_list_media_time_dts -= msc->dts_shift; - } - // While reordering frame index according to edit list we must handle properly // the scenario when edit list entry starts from none key frame. // We find closest previous key frame and preserve it and consequent frames in index. // All frames which are outside edit list entry time boundaries will be dropped after decoding. - search_timestamp = edit_list_media_time_dts; + search_timestamp = edit_list_media_time; if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // Audio decoders like AAC need need a decoder delay samples previous to the current sample, // to correctly decode this frame. Hence for audio we seek to a frame 1 sec. before the @@ -3141,42 +3463,27 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) search_timestamp = FFMAX(search_timestamp - msc->time_scale, e_old[0].timestamp); } - index = find_prev_closest_index(st, e_old, nb_old, search_timestamp, 0); - if (index == -1) { + if (find_prev_closest_index(st, e_old, nb_old, ctts_data_old, ctts_count_old, search_timestamp, 0, + &index, &ctts_index_old, &ctts_sample_old) < 0) { av_log(mov->fc, AV_LOG_WARNING, "st: %d edit list: %"PRId64" Missing key frame while searching for timestamp: %"PRId64"\n", st->index, edit_list_index, search_timestamp); - index = find_prev_closest_index(st, e_old, nb_old, search_timestamp, AVSEEK_FLAG_ANY); - - if (index == -1) { + if (find_prev_closest_index(st, e_old, nb_old, ctts_data_old, ctts_count_old, search_timestamp, AVSEEK_FLAG_ANY, + &index, &ctts_index_old, &ctts_sample_old) < 0) { av_log(mov->fc, AV_LOG_WARNING, - "st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n" - "Rounding edit list media time to zero.\n", + "st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n", st->index, edit_list_index, search_timestamp); index = 0; - edit_list_media_time = 0; + ctts_index_old = 0; + ctts_sample_old = 0; } } current = e_old + index; - - ctts_index_old = 0; - ctts_sample_old = 0; - - // set ctts_index properly for the found key frame - for (index_ctts_count = 0; index_ctts_count < index; index_ctts_count++) { - if (ctts_data_old && ctts_index_old < ctts_count_old) { - ctts_sample_old++; - if (ctts_data_old[ctts_index_old].count == ctts_sample_old) { - ctts_index_old++; - ctts_sample_old = 0; - } - } - } - edit_list_start_ctts_sample = ctts_sample_old; // Iterate over index and arrange it according to edit list edit_list_start_encountered = 0; + found_keyframe_after_edit = 0; for (; current < e_old_end; current++, index++) { // check if frame outside edit list mark it for discard frame_duration = (current + 1 < e_old_end) ? @@ -3249,7 +3556,6 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Increment skip_samples for the first non-zero audio edit list if (first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { st->skip_samples += frame_duration; - msc->start_pad = st->skip_samples; } } } @@ -3290,18 +3596,26 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } // Break when found first key frame after edit entry completion - if (((curr_cts + frame_duration) >= (edit_list_duration + edit_list_media_time)) && + if ((curr_cts + frame_duration >= (edit_list_duration + edit_list_media_time)) && ((flags & AVINDEX_KEYFRAME) || ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)))) { - - if (ctts_data_old && ctts_sample_old != 0) { - if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count, - &msc->ctts_allocated_size, - ctts_sample_old - edit_list_start_ctts_sample, - ctts_data_old[ctts_index_old].duration) == -1) { - av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n", - ctts_index_old, ctts_sample_old - edit_list_start_ctts_sample, - ctts_data_old[ctts_index_old].duration); - break; + if (ctts_data_old) { + // If we have CTTS and this is the first keyframe after edit elist, + // wait for one more, because there might be trailing B-frames after this I-frame + // that do belong to the edit. + if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO && found_keyframe_after_edit == 0) { + found_keyframe_after_edit = 1; + continue; + } + if (ctts_sample_old != 0) { + if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count, + &msc->ctts_allocated_size, + ctts_sample_old - edit_list_start_ctts_sample, + ctts_data_old[ctts_index_old].duration) == -1) { + av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n", + ctts_index_old, ctts_sample_old - edit_list_start_ctts_sample, + ctts_data_old[ctts_index_old].duration); + break; + } } } break; @@ -3323,10 +3637,12 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Update av stream length st->duration = edit_list_dts_entry_end - start_dts; + msc->start_pad = st->skip_samples; // Free the old index and the old CTTS structures av_free(e_old); av_free(ctts_data_old); + av_freep(&frame_duration_buffer); // Null terminate the index ranges array current_index_range++; @@ -3346,6 +3662,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int stps_index = 0; unsigned int i, j; uint64_t stream_size = 0; + MOVStts *ctts_data_old = sc->ctts_data; + unsigned int ctts_count_old = sc->ctts_count; if (sc->elst_count) { int i, edit_start_index = 0, multiple_edits = 0; @@ -3414,6 +3732,28 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries); + if (ctts_data_old) { + // Expand ctts entries such that we have a 1-1 mapping with samples + if (sc->sample_count >= UINT_MAX / sizeof(*sc->ctts_data)) + return; + sc->ctts_count = 0; + sc->ctts_allocated_size = 0; + sc->ctts_data = av_fast_realloc(NULL, &sc->ctts_allocated_size, + sc->sample_count * sizeof(*sc->ctts_data)); + if (!sc->ctts_data) { + av_free(ctts_data_old); + return; + } + for (i = 0; i < ctts_count_old && + sc->ctts_count < sc->sample_count; i++) + for (j = 0; j < ctts_data_old[i].count && + sc->ctts_count < sc->sample_count; j++) + add_ctts_entry(&sc->ctts_data, &sc->ctts_count, + &sc->ctts_allocated_size, 1, + ctts_data_old[i].duration); + av_free(ctts_data_old); + } + for (i = 0; i < sc->chunk_count; i++) { int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX; current_offset = sc->chunk_offsets[i]; @@ -3620,6 +3960,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) // Fix index according to edit lists. mov_fix_index(mov, st); } + + mov_estimate_video_delay(mov, st); } static int test_same_origin(const char *src, const char *ref) { @@ -3943,8 +4285,10 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) break; *p = av_malloc(len + 1); - if (!*p) + if (!*p) { + ret = AVERROR(ENOMEM); break; + } ret = ffio_read_size(pb, *p, len); if (ret < 0) { av_freep(p); @@ -4118,8 +4462,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVFragment *frag = &c->fragment; MOVTrackExt *trex = NULL; - MOVFragmentIndex* index = NULL; - int flags, track_id, i, found = 0; + int flags, track_id, i; avio_r8(pb); /* version */ flags = avio_rb24(pb); @@ -4128,6 +4471,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!track_id) return AVERROR_INVALIDDATA; frag->track_id = track_id; + set_frag_stream(&c->frag_index, track_id); for (i = 0; i < c->trex_count; i++) if (c->trex_data[i].track_id == frag->track_id) { trex = &c->trex_data[i]; @@ -4149,35 +4493,8 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb) : trex->size; frag->flags = flags & MOV_TFHD_DEFAULT_FLAGS ? avio_rb32(pb) : trex->flags; - frag->time = AV_NOPTS_VALUE; - for (i = 0; i < c->fragment_index_count; i++) { - int j; - MOVFragmentIndex* candidate = c->fragment_index_data[i]; - if (candidate->track_id == frag->track_id) { - av_log(c->fc, AV_LOG_DEBUG, - "found fragment index for track %u\n", frag->track_id); - index = candidate; - for (j = index->current_item; j < index->item_count; j++) { - if (frag->implicit_offset == index->items[j].moof_offset) { - av_log(c->fc, AV_LOG_DEBUG, "found fragment index entry " - "for track %u and moof_offset %"PRId64"\n", - frag->track_id, index->items[j].moof_offset); - frag->time = index->items[j].time; - index->current_item = j + 1; - found = 1; - break; - } - } - if (found) - break; - } - } - if (index && !found) { - av_log(c->fc, AV_LOG_DEBUG, "track %u has a fragment index but " - "it doesn't have an (in-order) entry for moof_offset " - "%"PRId64"\n", frag->track_id, frag->implicit_offset); - } av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags); + return 0; } @@ -4232,6 +4549,8 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st = NULL; MOVStreamContext *sc; int version, i; + MOVFragmentStreamInfo * frag_stream_info; + int64_t base_media_decode_time; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -4249,10 +4568,16 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom) version = avio_r8(pb); avio_rb24(pb); /* flags */ if (version) { - sc->track_end = avio_rb64(pb); + base_media_decode_time = avio_rb64(pb); } else { - sc->track_end = avio_rb32(pb); + base_media_decode_time = avio_rb32(pb); } + + frag_stream_info = get_current_frag_stream_info(&c->frag_index); + if (frag_stream_info) + frag_stream_info->tfdt_dts = base_media_decode_time; + sc->track_end = base_media_decode_time; + return 0; } @@ -4263,10 +4588,15 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVStreamContext *sc; MOVStts *ctts_data; uint64_t offset; - int64_t dts; + int64_t dts, pts = AV_NOPTS_VALUE; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; int flags, distance, i; + int64_t prev_dts = AV_NOPTS_VALUE; + int next_frag_index = -1, index_entry_pos; + size_t requested_size; + AVIndexEntry *new_entries; + MOVFragmentStreamInfo * frag_stream_info; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -4281,6 +4611,23 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc = st->priv_data; if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1) return 0; + + // Find the next frag_index index that has a valid index_entry for + // the current track_id. + // + // A valid index_entry means the trun for the fragment was read + // and it's samples are in index_entries at the given position. + // New index entries will be inserted before the index_entry found. + index_entry_pos = st->nb_index_entries; + for (i = c->frag_index.current + 1; i < c->frag_index.nb_items; i++) { + frag_stream_info = get_frag_stream_info(&c->frag_index, i, frag->track_id); + if (frag_stream_info && frag_stream_info->index_entry >= 0) { + next_frag_index = i; + index_entry_pos = frag_stream_info->index_entry; + break; + } + } + avio_r8(pb); /* version */ flags = avio_rb24(pb); entries = avio_rb32(pb); @@ -4290,18 +4637,99 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb); if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); - dts = sc->track_end - sc->time_offset; - offset = frag->base_data_offset + data_offset; + + frag_stream_info = get_current_frag_stream_info(&c->frag_index); + if (frag_stream_info) + { + if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && + c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) { + pts = frag_stream_info->first_tfra_pts; + av_log(c->fc, AV_LOG_DEBUG, "found mfra time %"PRId64 + ", using it for pts\n", pts); + } else if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) { + // FIXME: sidx earliest_presentation_time is *PTS*, s.b. + // pts = frag_stream_info->sidx_pts; + dts = frag_stream_info->sidx_pts - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found sidx time %"PRId64 + ", using it for pts\n", pts); + } else if (frag_stream_info->tfdt_dts != AV_NOPTS_VALUE) { + dts = frag_stream_info->tfdt_dts - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found tfdt time %"PRId64 + ", using it for dts\n", dts); + } else { + dts = sc->track_end - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found track end time %"PRId64 + ", using it for dts\n", dts); + } + } else { + dts = sc->track_end - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found track end time %"PRId64 + ", using it for dts\n", dts); + } + offset = frag->base_data_offset + data_offset; distance = 0; av_log(c->fc, AV_LOG_TRACE, "first sample flags 0x%x\n", first_sample_flags); + + // realloc space for new index entries + if((unsigned)st->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) { + entries = UINT_MAX / sizeof(AVIndexEntry) - st->nb_index_entries; + av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); + } + if (entries <= 0) + return -1; + + requested_size = (st->nb_index_entries + entries) * sizeof(AVIndexEntry); + new_entries = av_fast_realloc(st->index_entries, + &st->index_entries_allocated_size, + requested_size); + if(!new_entries) + return AVERROR(ENOMEM); + st->index_entries= new_entries; + + requested_size = (st->nb_index_entries + entries) * sizeof(*sc->ctts_data); + ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, + requested_size); + if (!ctts_data) + return AVERROR(ENOMEM); + sc->ctts_data = ctts_data; + + // In case there were samples without ctts entries, ensure they get + // zero valued entries. This ensures clips which mix boxes with and + // without ctts entries don't pickup uninitialized data. + memset(sc->ctts_data + sc->ctts_count, 0, + (st->nb_index_entries - sc->ctts_count) * sizeof(*sc->ctts_data)); + + if (index_entry_pos < st->nb_index_entries) { + // Make hole in index_entries and ctts_data for new samples + memmove(st->index_entries + index_entry_pos + entries, + st->index_entries + index_entry_pos, + sizeof(*st->index_entries) * + (st->nb_index_entries - index_entry_pos)); + memmove(sc->ctts_data + index_entry_pos + entries, + sc->ctts_data + index_entry_pos, + sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos)); + if (index_entry_pos < sc->current_sample) { + sc->current_sample += entries; + } + } + + st->nb_index_entries += entries; + sc->ctts_count = st->nb_index_entries; + + // Record the index_entry position in frag_index of this fragment + if (frag_stream_info) + frag_stream_info->index_entry = index_entry_pos; + + if (index_entry_pos > 0) + prev_dts = st->index_entries[index_entry_pos-1].timestamp; + for (i = 0; i < entries && !pb->eof_reached; i++) { unsigned sample_size = frag->size; int sample_flags = i ? frag->flags : first_sample_flags; unsigned sample_duration = frag->duration; unsigned ctts_duration = 0; int keyframe = 0; - int ctts_index = 0; - int old_nb_index_entries = st->nb_index_entries; + int index_entry_flags = 0; if (flags & MOV_TRUN_SAMPLE_DURATION) sample_duration = avio_rb32(pb); if (flags & MOV_TRUN_SAMPLE_SIZE) sample_size = avio_rb32(pb); @@ -4309,27 +4737,22 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (flags & MOV_TRUN_SAMPLE_CTS) ctts_duration = avio_rb32(pb); mov_update_dts_shift(sc, ctts_duration); - if (frag->time != AV_NOPTS_VALUE) { - if (c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) { - int64_t pts = frag->time; - av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64 - " sc->dts_shift %d ctts.duration %d" - " sc->time_offset %"PRId64" flags & MOV_TRUN_SAMPLE_CTS %d\n", pts, - sc->dts_shift, ctts_duration, - sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS); - dts = pts - sc->dts_shift; - if (flags & MOV_TRUN_SAMPLE_CTS) { - dts -= ctts_duration; - } else { - dts -= sc->time_offset; - } - av_log(c->fc, AV_LOG_DEBUG, "calculated into dts %"PRId64"\n", dts); + if (pts != AV_NOPTS_VALUE) { + dts = pts - sc->dts_shift; + if (flags & MOV_TRUN_SAMPLE_CTS) { + dts -= ctts_duration; } else { - dts = frag->time - sc->time_offset; - av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64 - ", using it for dts\n", dts); + dts -= sc->time_offset; } - frag->time = AV_NOPTS_VALUE; + av_log(c->fc, AV_LOG_DEBUG, + "pts %"PRId64" calculated dts %"PRId64 + " sc->dts_shift %d ctts.duration %d" + " sc->time_offset %"PRId64 + " flags & MOV_TRUN_SAMPLE_CTS %d\n", + pts, dts, + sc->dts_shift, ctts_duration, + sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS); + pts = AV_NOPTS_VALUE; } if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) @@ -4338,47 +4761,28 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) keyframe = !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC | MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES)); - if (keyframe) + if (keyframe) { distance = 0; - ctts_index = av_add_index_entry(st, offset, dts, sample_size, distance, - keyframe ? AVINDEX_KEYFRAME : 0); - if (ctts_index >= 0 && old_nb_index_entries < st->nb_index_entries) { - unsigned int size_needed = st->nb_index_entries * sizeof(*sc->ctts_data); - unsigned int request_size = size_needed > sc->ctts_allocated_size ? - FFMAX(size_needed, 2 * sc->ctts_allocated_size) : size_needed; - unsigned int old_ctts_size = sc->ctts_allocated_size; - ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, request_size); - if (!ctts_data) { - av_freep(&sc->ctts_data); - return AVERROR(ENOMEM); - } - sc->ctts_data = ctts_data; - - // In case there were samples without ctts entries, ensure they get - // zero valued entries. This ensures clips which mix boxes with and - // without ctts entries don't pickup uninitialized data. - memset((uint8_t*)(sc->ctts_data) + old_ctts_size, 0, sc->ctts_allocated_size - old_ctts_size); - - if (ctts_index != old_nb_index_entries) { - memmove(sc->ctts_data + ctts_index + 1, sc->ctts_data + ctts_index, - sizeof(*sc->ctts_data) * (sc->ctts_count - ctts_index)); - if (ctts_index <= sc->current_sample) { - // if we inserted a new item before the current sample, move the - // counter ahead so it is still pointing to the same sample. - sc->current_sample++; - } - } - - sc->ctts_data[ctts_index].count = 1; - sc->ctts_data[ctts_index].duration = ctts_duration; - sc->ctts_count++; - } else { - av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); + index_entry_flags |= AVINDEX_KEYFRAME; } + // Fragments can overlap in time. Discard overlapping frames after + // decoding. + if (prev_dts >= dts) + index_entry_flags |= AVINDEX_DISCARD_FRAME; + + st->index_entries[index_entry_pos].pos = offset; + st->index_entries[index_entry_pos].timestamp = dts; + st->index_entries[index_entry_pos].size= sample_size; + st->index_entries[index_entry_pos].min_distance= distance; + st->index_entries[index_entry_pos].flags = index_entry_flags; + + sc->ctts_data[index_entry_pos].count = 1; + sc->ctts_data[index_entry_pos].duration = ctts_duration; + index_entry_pos++; av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " - "size %u, distance %d, keyframe %d\n", st->index, ctts_index, - offset, dts, sample_size, distance, keyframe); + "size %u, distance %d, keyframe %d\n", st->index, + index_entry_pos, offset, dts, sample_size, distance, keyframe); distance++; dts += sample_duration; offset += sample_size; @@ -4386,9 +4790,49 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->duration_for_fps += sample_duration; sc->nb_frames_for_fps ++; } + if (i < entries) { + // EOF found before reading all entries. Fix the hole this would + // leave in index_entries and ctts_data + int gap = entries - i; + memmove(st->index_entries + index_entry_pos, + st->index_entries + index_entry_pos + gap, + sizeof(*st->index_entries) * + (st->nb_index_entries - (index_entry_pos + gap))); + memmove(sc->ctts_data + index_entry_pos, + sc->ctts_data + index_entry_pos + gap, + sizeof(*sc->ctts_data) * + (sc->ctts_count - (index_entry_pos + gap))); - if (pb->eof_reached) + st->nb_index_entries -= gap; + sc->ctts_count -= gap; + if (index_entry_pos < sc->current_sample) { + sc->current_sample -= gap; + } + entries = i; + } + + // The end of this new fragment may overlap in time with the start + // of the next fragment in index_entries. Mark the samples in the next + // fragment that overlap with AVINDEX_DISCARD_FRAME + prev_dts = AV_NOPTS_VALUE; + if (index_entry_pos > 0) + prev_dts = st->index_entries[index_entry_pos-1].timestamp; + for (i = index_entry_pos; i < st->nb_index_entries; i++) { + if (prev_dts < st->index_entries[i].timestamp) + break; + st->index_entries[i].flags |= AVINDEX_DISCARD_FRAME; + } + + // If a hole was created to insert the new index_entries into, + // the index_entry recorded for all subsequent moof must + // be incremented by the number of entries inserted. + fix_frag_index_entries(&c->frag_index, next_frag_index, + frag->track_id, entries); + + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted TRUN atom\n"); return AVERROR_EOF; + } frag->implicit_offset = offset; @@ -4401,14 +4845,12 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - int64_t offset = avio_tell(pb) + atom.size, pts; + int64_t offset = avio_tell(pb) + atom.size, pts, timestamp; uint8_t version; - unsigned i, track_id; + unsigned i, j, track_id, item_count; AVStream *st = NULL; AVStream *ref_st = NULL; MOVStreamContext *sc, *ref_sc = NULL; - MOVFragmentIndex *index = NULL; - MOVFragmentIndex **tmp; AVRational timescale; version = avio_r8(pb); @@ -4450,57 +4892,46 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb16(pb); // reserved - index = av_mallocz(sizeof(MOVFragmentIndex)); - if (!index) - return AVERROR(ENOMEM); + item_count = avio_rb16(pb); - index->track_id = track_id; - - index->item_count = avio_rb16(pb); - index->items = av_mallocz_array(index->item_count, sizeof(MOVFragmentIndexItem)); - - if (!index->items) { - av_freep(&index); - return AVERROR(ENOMEM); - } - - for (i = 0; i < index->item_count; i++) { + for (i = 0; i < item_count; i++) { + int index; + MOVFragmentStreamInfo * frag_stream_info; uint32_t size = avio_rb32(pb); uint32_t duration = avio_rb32(pb); if (size & 0x80000000) { avpriv_request_sample(c->fc, "sidx reference_type 1"); - av_freep(&index->items); - av_freep(&index); return AVERROR_PATCHWELCOME; } avio_rb32(pb); // sap_flags - index->items[i].moof_offset = offset; - index->items[i].time = av_rescale_q(pts, st->time_base, timescale); + timestamp = av_rescale_q(pts, st->time_base, timescale); + + index = update_frag_index(c, offset); + frag_stream_info = get_frag_stream_info(&c->frag_index, index, track_id); + if (frag_stream_info) + frag_stream_info->sidx_pts = timestamp; + offset += size; pts += duration; } st->duration = sc->track_end = pts; - tmp = av_realloc_array(c->fragment_index_data, - c->fragment_index_count + 1, - sizeof(MOVFragmentIndex*)); - if (!tmp) { - av_freep(&index->items); - av_freep(&index); - return AVERROR(ENOMEM); - } - - c->fragment_index_data = tmp; - c->fragment_index_data[c->fragment_index_count++] = index; sc->has_sidx = 1; if (offset == avio_size(pb)) { - for (i = 0; i < c->fc->nb_streams; i++) { - if (c->fc->streams[i]->id == c->fragment_index_data[0]->track_id) { - ref_st = c->fc->streams[i]; - ref_sc = ref_st->priv_data; - break; + // Find first entry in fragment index that came from an sidx. + // This will pretty much always be the first entry. + for (i = 0; i < c->frag_index.nb_items; i++) { + MOVFragmentIndexItem * item = &c->frag_index.item[i]; + for (j = 0; ref_st == NULL && j < item->nb_stream_info; j++) { + MOVFragmentStreamInfo * si; + si = &item->stream_info[j]; + if (si->sidx_pts != AV_NOPTS_VALUE) { + ref_st = c->fc->streams[j]; + ref_sc = ref_st->priv_data; + break; + } } } for (i = 0; i < c->fc->nb_streams; i++) { @@ -4511,7 +4942,7 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } - c->fragment_index_complete = 1; + c->frag_index.complete = 1; } return 0; @@ -4574,6 +5005,7 @@ static int mov_read_cmov(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) goto free_and_return; + ret = AVERROR_INVALIDDATA; if (uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) goto free_and_return; if (ffio_init_context(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL) != 0) @@ -4597,6 +5029,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; int i, edit_count, version; + int64_t elst_entry_size; if (c->fc->nb_streams < 1 || c->ignore_editlist) return 0; @@ -4605,6 +5038,21 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) version = avio_r8(pb); /* version */ avio_rb24(pb); /* flags */ edit_count = avio_rb32(pb); /* entries */ + atom.size -= 8; + + elst_entry_size = version == 1 ? 20 : 12; + if (atom.size != edit_count * elst_entry_size) { + if (c->fc->strict_std_compliance >= FF_COMPLIANCE_STRICT) { + av_log(c->fc, AV_LOG_ERROR, "Invalid edit list entry_count: %d for elst atom of size: %"PRId64" bytes.\n", + edit_count, atom.size + 8); + return AVERROR_INVALIDDATA; + } else { + edit_count = atom.size / elst_entry_size; + if (edit_count * elst_entry_size != atom.size) { + av_log(c->fc, AV_LOG_WARNING, "ELST atom of %"PRId64" bytes, bigger than %d entries.", atom.size, edit_count); + } + } + } if (!edit_count) return 0; @@ -4617,17 +5065,20 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR(ENOMEM); av_log(c->fc, AV_LOG_TRACE, "track[%u].edit_count = %i\n", c->fc->nb_streams - 1, edit_count); - for (i = 0; i < edit_count && !pb->eof_reached; i++) { + for (i = 0; i < edit_count && atom.size > 0 && !pb->eof_reached; i++) { MOVElst *e = &sc->elst_data[i]; if (version == 1) { e->duration = avio_rb64(pb); e->time = avio_rb64(pb); + atom.size -= 16; } else { e->duration = avio_rb32(pb); /* segment duration */ e->time = (int32_t)avio_rb32(pb); /* media time */ + atom.size -= 8; } e->rate = avio_rb32(pb) / 65536.0; + atom.size -= 4; av_log(c->fc, AV_LOG_TRACE, "duration=%"PRId64" time=%"PRId64" rate=%f\n", e->duration, e->time, e->rate); @@ -4744,6 +5195,45 @@ static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_mdcv(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + const int mapping[3] = {1, 2, 0}; + const int chroma_den = 50000; + const int luma_den = 10000; + int i; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 24) { + av_log(c->fc, AV_LOG_ERROR, "Invalid Mastering Display Color Volume box\n"); + return AVERROR_INVALIDDATA; + } + + sc->mastering = av_mastering_display_metadata_alloc(); + if (!sc->mastering) + return AVERROR(ENOMEM); + + for (i = 0; i < 3; i++) { + const int j = mapping[i]; + sc->mastering->display_primaries[j][0] = av_make_q(avio_rb16(pb), chroma_den); + sc->mastering->display_primaries[j][1] = av_make_q(avio_rb16(pb), chroma_den); + } + sc->mastering->white_point[0] = av_make_q(avio_rb16(pb), chroma_den); + sc->mastering->white_point[1] = av_make_q(avio_rb16(pb), chroma_den); + + sc->mastering->max_luminance = av_make_q(avio_rb32(pb), luma_den); + sc->mastering->min_luminance = av_make_q(avio_rb32(pb), luma_den); + + sc->mastering->has_luminance = 1; + sc->mastering->has_primaries = 1; + + return 0; +} + static int mov_read_coll(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; @@ -4776,6 +5266,30 @@ static int mov_read_coll(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_clli(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 4) { + av_log(c->fc, AV_LOG_ERROR, "Empty Content Light Level Info box\n"); + return AVERROR_INVALIDDATA; + } + + sc->coll = av_content_light_metadata_alloc(&sc->coll_size); + if (!sc->coll) + return AVERROR(ENOMEM); + + sc->coll->MaxCLL = avio_rb16(pb); + sc->coll->MaxFALL = avio_rb16(pb); + + return 0; +} + static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -4823,7 +5337,7 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - int size, layout; + int size, version, layout; int32_t yaw, pitch, roll; uint32_t l = 0, t = 0, r = 0, b = 0; uint32_t tag, padding = 0; @@ -4849,7 +5363,13 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_ERROR, "Missing spherical video header\n"); return 0; } - avio_skip(pb, 4); /* version + flags */ + version = avio_r8(pb); + if (version != 0) { + av_log(c->fc, AV_LOG_WARNING, "Unknown spherical version %d\n", + version); + return 0; + } + avio_skip(pb, 3); /* flags */ avio_skip(pb, size - 12); /* metadata_source */ size = avio_rb32(pb); @@ -4871,7 +5391,13 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_ERROR, "Missing projection header box\n"); return 0; } - avio_skip(pb, 4); /* version + flags */ + version = avio_r8(pb); + if (version != 0) { + av_log(c->fc, AV_LOG_WARNING, "Unknown spherical version %d\n", + version); + return 0; + } + avio_skip(pb, 3); /* flags */ /* 16.16 fixed point */ yaw = avio_rb32(pb); @@ -4883,7 +5409,13 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; tag = avio_rl32(pb); - avio_skip(pb, 4); /* version + flags */ + version = avio_r8(pb); + if (version != 0) { + av_log(c->fc, AV_LOG_WARNING, "Unknown spherical version %d\n", + version); + return 0; + } + avio_skip(pb, 3); /* flags */ switch (tag) { case MKTAG('c','b','m','p'): layout = avio_rb32(pb); @@ -4953,7 +5485,8 @@ static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_ goto out; /* Check for mandatory keys and values, try to support XML as best-effort */ - if (av_stristr(buffer, "") && + if (!sc->spherical && + av_stristr(buffer, "") && (val = av_stristr(buffer, "")) && av_stristr(val, "true") && (val = av_stristr(buffer, "")) && @@ -4966,7 +5499,7 @@ static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_ sc->spherical->projection = AV_SPHERICAL_EQUIRECTANGULAR; - if (av_stristr(buffer, "")) { + if (av_stristr(buffer, "") && !sc->stereo3d) { enum AVStereo3DType mode; if (av_stristr(buffer, "left-right")) @@ -5108,7 +5641,8 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) return ret; if (!sc->spherical) - av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n"); } + av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n"); + } return 0; } @@ -5565,6 +6099,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('S','m','D','m'), mov_read_smdm }, { MKTAG('C','o','L','L'), mov_read_coll }, { MKTAG('v','p','c','C'), mov_read_vpcc }, +{ MKTAG('m','d','c','v'), mov_read_mdcv }, +{ MKTAG('c','l','l','i'), mov_read_clli }, { 0, NULL } }; @@ -5661,9 +6197,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) return err; } if (c->found_moov && c->found_mdat && - ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) || + ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) || start_pos + a.size == avio_size(pb))) { - if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) + if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) c->next_root_atom = start_pos + a.size; c->atom_depth --; return 0; @@ -6008,12 +6544,10 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->trex_data); av_freep(&mov->bitrates); - for (i = 0; i < mov->fragment_index_count; i++) { - MOVFragmentIndex* index = mov->fragment_index_data[i]; - av_freep(&index->items); - av_freep(&mov->fragment_index_data[i]); + for (i = 0; i < mov->frag_index.nb_items; i++) { + av_freep(&mov->frag_index.item[i].stream_info); } - av_freep(&mov->fragment_index_data); + av_freep(&mov->frag_index.item); av_freep(&mov->aes_decrypt); av_freep(&mov->chapter_tracks); @@ -6057,48 +6591,27 @@ static void export_orphan_timecode(AVFormatContext *s) static int read_tfra(MOVContext *mov, AVIOContext *f) { - MOVFragmentIndex* index = NULL; int version, fieldlength, i, j; int64_t pos = avio_tell(f); uint32_t size = avio_rb32(f); - void *tmp; + unsigned track_id, item_count; if (avio_rb32(f) != MKBETAG('t', 'f', 'r', 'a')) { return 1; } av_log(mov->fc, AV_LOG_VERBOSE, "found tfra\n"); - index = av_mallocz(sizeof(MOVFragmentIndex)); - if (!index) { - return AVERROR(ENOMEM); - } - - tmp = av_realloc_array(mov->fragment_index_data, - mov->fragment_index_count + 1, - sizeof(MOVFragmentIndex*)); - if (!tmp) { - av_freep(&index); - return AVERROR(ENOMEM); - } - mov->fragment_index_data = tmp; - mov->fragment_index_data[mov->fragment_index_count++] = index; version = avio_r8(f); avio_rb24(f); - index->track_id = avio_rb32(f); + track_id = avio_rb32(f); fieldlength = avio_rb32(f); - index->item_count = avio_rb32(f); - index->items = av_mallocz_array( - index->item_count, sizeof(MOVFragmentIndexItem)); - if (!index->items) { - index->item_count = 0; - return AVERROR(ENOMEM); - } - for (i = 0; i < index->item_count; i++) { + item_count = avio_rb32(f); + for (i = 0; i < item_count; i++) { int64_t time, offset; + int index; + MOVFragmentStreamInfo * frag_stream_info; if (avio_feof(f)) { - index->item_count = 0; - av_freep(&index->items); return AVERROR_INVALIDDATA; } @@ -6109,8 +6622,16 @@ static int read_tfra(MOVContext *mov, AVIOContext *f) time = avio_rb32(f); offset = avio_rb32(f); } - index->items[i].time = time; - index->items[i].moof_offset = offset; + + // The first sample of each stream in a fragment is always a random + // access sample. So it's entry in the tfra can be used as the + // initial PTS of the fragment. + index = update_frag_index(mov, offset); + frag_stream_info = get_frag_stream_info(&mov->frag_index, index, track_id); + if (frag_stream_info && + frag_stream_info->first_tfra_pts == AV_NOPTS_VALUE) + frag_stream_info->first_tfra_pts = time; + for (j = 0; j < ((fieldlength >> 4) & 3) + 1; j++) avio_r8(f); for (j = 0; j < ((fieldlength >> 2) & 3) + 1; j++) @@ -6192,13 +6713,13 @@ static int mov_read_header(AVFormatContext *s) /* check MOV header */ do { - if (mov->moov_retry) - avio_seek(pb, 0, SEEK_SET); - if ((err = mov_read_default(mov, pb, atom)) < 0) { - av_log(s, AV_LOG_ERROR, "error reading header\n"); - mov_read_close(s); - return err; - } + if (mov->moov_retry) + avio_seek(pb, 0, SEEK_SET); + if ((err = mov_read_default(mov, pb, atom)) < 0) { + av_log(s, AV_LOG_ERROR, "error reading header\n"); + mov_read_close(s); + return err; + } } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++); if (!mov->found_moov) { av_log(s, AV_LOG_ERROR, "moov atom not found\n"); @@ -6371,12 +6892,9 @@ static int mov_read_header(AVFormatContext *s) } ff_configure_buffers_for_index(s, AV_TIME_BASE); - for (i = 0; i < mov->fragment_index_count; i++) { - MOVFragmentIndex *idx = mov->fragment_index_data[i]; - for (j = 0; j < idx->item_count; j++) - if (idx->items[j].moof_offset <= mov->fragment.moof_offset) - idx->items[j].headers_read = 1; - } + for (i = 0; i < mov->frag_index.nb_items; i++) + if (mov->frag_index.item[i].moof_offset <= mov->fragment.moof_offset) + mov->frag_index.item[i].headers_read = 1; return 0; } @@ -6414,46 +6932,35 @@ static int should_retry(AVIOContext *pb, int error_code) { return 1; } -static int mov_switch_root(AVFormatContext *s, int64_t target) +static int mov_switch_root(AVFormatContext *s, int64_t target, int index) { + int ret; MOVContext *mov = s->priv_data; - int i, j; - int already_read = 0; + if (index >= 0 && index < mov->frag_index.nb_items) + target = mov->frag_index.item[index].moof_offset; if (avio_seek(s->pb, target, SEEK_SET) != target) { av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": partial file\n", target); return AVERROR_INVALIDDATA; } mov->next_root_atom = 0; - - for (i = 0; i < mov->fragment_index_count; i++) { - MOVFragmentIndex *index = mov->fragment_index_data[i]; - int found = 0; - for (j = 0; j < index->item_count; j++) { - MOVFragmentIndexItem *item = &index->items[j]; - if (found) { - mov->next_root_atom = item->moof_offset; - break; // Advance to next index in outer loop - } else if (item->moof_offset == target) { - index->current_item = FFMIN(j, index->current_item); - if (item->headers_read) - already_read = 1; - item->headers_read = 1; - found = 1; - } - } - if (!found) - index->current_item = 0; + if (index < 0 || index >= mov->frag_index.nb_items) + index = search_frag_moof_offset(&mov->frag_index, target); + if (index < mov->frag_index.nb_items) { + if (index + 1 < mov->frag_index.nb_items) + mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; + if (mov->frag_index.item[index].headers_read) + return 0; + mov->frag_index.item[index].headers_read = 1; } - if (already_read) - return 0; - mov->found_mdat = 0; - if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || - avio_feof(s->pb)) + ret = mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }); + if (ret < 0) + return ret; + if (avio_feof(s->pb)) return AVERROR_EOF; av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb)); @@ -6497,7 +7004,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) if (!sample || (mov->next_root_atom && sample->pos > mov->next_root_atom)) { if (!mov->next_root_atom) return AVERROR_EOF; - if ((ret = mov_switch_root(s, mov->next_root_atom)) < 0) + if ((ret = mov_switch_root(s, mov->next_root_atom, -1)) < 0) return ret; goto retry; } @@ -6621,25 +7128,18 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp) { MOVContext *mov = s->priv_data; - MOVStreamContext *sc = st->priv_data; - int i, j; + int index; - if (!mov->fragment_index_complete) + if (!mov->frag_index.complete) return 0; - for (i = 0; i < mov->fragment_index_count; i++) { - if (mov->fragment_index_data[i]->track_id == st->id || !sc->has_sidx) { - MOVFragmentIndex *index = mov->fragment_index_data[i]; - for (j = index->item_count - 1; j >= 0; j--) { - if (index->items[j].time <= timestamp) { - if (index->items[j].headers_read) - return 0; - - return mov_switch_root(s, index->items[j].moof_offset); - } - } - } - } + index = search_frag_timestamp(&mov->frag_index, st, timestamp); + if (index < 0) + index = 0; + if (!mov->frag_index.item[index].headers_read) + return mov_switch_root(s, -1, index); + if (index + 1 < mov->frag_index.nb_items) + mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; return 0; } @@ -6647,10 +7147,12 @@ static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, int flags) { MOVStreamContext *sc = st->priv_data; - int sample, time_sample; + int sample, time_sample, ret; unsigned int i; - int ret = mov_seek_fragment(s, st, timestamp); + timestamp -= sc->time_offset; + + ret = mov_seek_fragment(s, st, timestamp); if (ret < 0) return ret; diff --git a/libavutil/tests/atomic.c b/libavformat/mov_esds.c similarity index 56% rename from libavutil/tests/atomic.c rename to libavformat/mov_esds.c index e41bf5a2b..a444d969c 100644 --- a/libavutil/tests/atomic.c +++ b/libavformat/mov_esds.c @@ -16,23 +16,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/atomic.h" -#include "libavutil/avassert.h" +#include "avformat.h" +#include "avio.h" +#include "isom.h" -int main(void) +int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb) { - volatile int val = 1; - void *tmp1 = (int *)&val; - void * volatile *tmp2 = &tmp1; - int res; + AVStream *st; + int tag, ret = 0; - res = avpriv_atomic_int_add_and_fetch(&val, 1); - av_assert0(res == 2); - avpriv_atomic_int_set(&val, 3); - res = avpriv_atomic_int_get(&val); - av_assert0(res == 3); - avpriv_atomic_ptr_cas(tmp2, tmp1, &res); - av_assert0(*tmp2 == &res); + if (fc->nb_streams < 1) + return 0; + st = fc->streams[fc->nb_streams-1]; - return 0; + avio_rb32(pb); /* version + flags */ + ff_mp4_read_descr(fc, pb, &tag); + if (tag == MP4ESDescrTag) { + ff_mp4_parse_es_descr(pb, NULL); + } else + avio_rb16(pb); /* ID */ + + ff_mp4_read_descr(fc, pb, &tag); + if (tag == MP4DecConfigDescrTag) + ret = ff_mp4_read_dec_config_descr(fc, st, pb); + + return ret; } diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 283828614..a597b0853 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -31,7 +31,7 @@ #include "avio.h" #include "isom.h" #include "avc.h" -#include "libavcodec/ac3_parser.h" +#include "libavcodec/ac3_parser_internal.h" #include "libavcodec/dnxhddata.h" #include "libavcodec/flac.h" #include "libavcodec/get_bits.h" @@ -252,6 +252,30 @@ static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag) return update_size(pb, pos); } +/* Sample dependency atom */ +static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track) +{ + int i; + uint8_t leading, dependent, reference, redundancy; + int64_t pos = avio_tell(pb); + avio_wb32(pb, 0); // size + ffio_wfourcc(pb, "sdtp"); + avio_wb32(pb, 0); // version & flags + for (i = 0; i < track->entry; i++) { + dependent = MOV_SAMPLE_DEPENDENCY_YES; + leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN; + if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) { + reference = MOV_SAMPLE_DEPENDENCY_NO; + } + if (track->cluster[i].flags & MOV_SYNC_SAMPLE) { + dependent = MOV_SAMPLE_DEPENDENCY_NO; + } + avio_w8(pb, (leading << 6) | (dependent << 4) | + (reference << 2) | redundancy); + } + return update_size(pb, pos); +} + static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track) { avio_wb32(pb, 0x11); /* size */ @@ -345,23 +369,22 @@ struct eac3_info { #if CONFIG_AC3_PARSER static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) { - GetBitContext gbc; - AC3HeaderInfo tmp, *hdr = &tmp; + AC3HeaderInfo *hdr = NULL; struct eac3_info *info; - int num_blocks; + int num_blocks, ret; if (!track->eac3_priv && !(track->eac3_priv = av_mallocz(sizeof(*info)))) return AVERROR(ENOMEM); info = track->eac3_priv; - init_get_bits(&gbc, pkt->data, pkt->size * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) { + if (avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size) < 0) { /* drop the packets until we see a good one */ if (!track->entry) { av_log(mov, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n"); - return 0; - } - return AVERROR_INVALIDDATA; + ret = 0; + } else + ret = AVERROR_INVALIDDATA; + goto end; } info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000); @@ -369,20 +392,25 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) if (!info->ec3_done) { /* AC-3 substream must be the first one */ - if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) - return AVERROR(EINVAL); + if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) { + ret = AVERROR(EINVAL); + goto end; + } /* this should always be the case, given that our AC-3 parser * concatenates dependent frames to their independent parent */ if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { /* substream ids must be incremental */ - if (hdr->substreamid > info->num_ind_sub + 1) - return AVERROR(EINVAL); + if (hdr->substreamid > info->num_ind_sub + 1) { + ret = AVERROR(EINVAL); + goto end; + } if (hdr->substreamid == info->num_ind_sub + 1) { //info->num_ind_sub++; avpriv_request_sample(track->par, "Multiple independent substreams"); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto end; } else if (hdr->substreamid < info->num_ind_sub || hdr->substreamid == 0 && info->substream[0].bsid) { info->ec3_done = 1; @@ -403,16 +431,20 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) int parent = hdr->substreamid; while (cumul_size != pkt->size) { + GetBitContext gbc; int i; - init_get_bits(&gbc, pkt->data + cumul_size, (pkt->size - cumul_size) * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) - return AVERROR_INVALIDDATA; - if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) - return AVERROR(EINVAL); - cumul_size += hdr->frame_size; + ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size); + if (ret < 0) + goto end; + if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) { + ret = AVERROR(EINVAL); + goto end; + } info->substream[parent].num_dep_sub++; + ret /= 8; /* header is parsed up to lfeon, but custom channel map may be needed */ + init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret); /* skip bsid */ skip_bits(&gbc, 5); /* skip volume control params */ @@ -427,42 +459,49 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f; else info->substream[parent].chan_loc |= hdr->channel_mode; + cumul_size += hdr->frame_size; } } } concatenate: - if (!info->num_blocks && num_blocks == 6) - return pkt->size; - else if (info->num_blocks + num_blocks > 6) - return AVERROR_INVALIDDATA; + if (!info->num_blocks && num_blocks == 6) { + ret = pkt->size; + goto end; + } + else if (info->num_blocks + num_blocks > 6) { + ret = AVERROR_INVALIDDATA; + goto end; + } if (!info->num_blocks) { - int ret = av_packet_ref(&info->pkt, pkt); - if (ret < 0) - return ret; - info->num_blocks = num_blocks; - return 0; + ret = av_packet_ref(&info->pkt, pkt); + if (!ret) + info->num_blocks = num_blocks; + goto end; } else { - int ret; if ((ret = av_grow_packet(&info->pkt, pkt->size)) < 0) - return ret; + goto end; memcpy(info->pkt.data + info->pkt.size - pkt->size, pkt->data, pkt->size); info->num_blocks += num_blocks; info->pkt.duration += pkt->duration; if ((ret = av_copy_packet_side_data(&info->pkt, pkt)) < 0) - return ret; + goto end; if (info->num_blocks != 6) - return 0; + goto end; av_packet_unref(pkt); ret = av_packet_ref(pkt, &info->pkt); if (ret < 0) - return ret; + goto end; av_packet_unref(&info->pkt); info->num_blocks = 0; } + ret = pkt->size; - return pkt->size; +end: + av_free(hdr); + + return ret; } #endif @@ -1671,6 +1710,21 @@ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMa return update_size(pb, sv3d_pos); } +static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track) +{ + avio_wb32(pb, 40); + ffio_wfourcc(pb, "clap"); + avio_wb32(pb, track->par->width); /* apertureWidth_N */ + avio_wb32(pb, 1); /* apertureWidth_D (= 1) */ + avio_wb32(pb, track->height); /* apertureHeight_N */ + avio_wb32(pb, 1); /* apertureHeight_D (= 1) */ + avio_wb32(pb, 0); /* horizOff_N (= 0) */ + avio_wb32(pb, 1); /* horizOff_D (= 1) */ + avio_wb32(pb, 0); /* vertOff_N (= 0) */ + avio_wb32(pb, 1); /* vertOff_D (= 1) */ + return 40; +} + static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) { AVRational sar; @@ -1755,23 +1809,30 @@ static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "nclc"); switch (track->par->color_primaries) { case AVCOL_PRI_BT709: avio_wb16(pb, 1); break; + case AVCOL_PRI_BT470BG: avio_wb16(pb, 5); break; case AVCOL_PRI_SMPTE170M: case AVCOL_PRI_SMPTE240M: avio_wb16(pb, 6); break; - case AVCOL_PRI_BT470BG: avio_wb16(pb, 5); break; + case AVCOL_PRI_BT2020: avio_wb16(pb, 9); break; + case AVCOL_PRI_SMPTE431: avio_wb16(pb, 11); break; + case AVCOL_PRI_SMPTE432: avio_wb16(pb, 12); break; default: avio_wb16(pb, 2); } switch (track->par->color_trc) { - case AVCOL_TRC_BT709: avio_wb16(pb, 1); break; - case AVCOL_TRC_SMPTE170M: avio_wb16(pb, 1); break; // remapped - case AVCOL_TRC_SMPTE240M: avio_wb16(pb, 7); break; - default: avio_wb16(pb, 2); + case AVCOL_TRC_BT709: avio_wb16(pb, 1); break; + case AVCOL_TRC_SMPTE170M: avio_wb16(pb, 1); break; // remapped + case AVCOL_TRC_SMPTE240M: avio_wb16(pb, 7); break; + case AVCOL_TRC_SMPTEST2084: avio_wb16(pb, 16); break; + case AVCOL_TRC_SMPTE428: avio_wb16(pb, 17); break; + case AVCOL_TRC_ARIB_STD_B67: avio_wb16(pb, 18); break; + default: avio_wb16(pb, 2); } switch (track->par->color_space) { - case AVCOL_SPC_BT709: avio_wb16(pb, 1); break; + case AVCOL_SPC_BT709: avio_wb16(pb, 1); break; case AVCOL_SPC_BT470BG: - case AVCOL_SPC_SMPTE170M: avio_wb16(pb, 6); break; - case AVCOL_SPC_SMPTE240M: avio_wb16(pb, 7); break; - default: avio_wb16(pb, 2); + case AVCOL_SPC_SMPTE170M: avio_wb16(pb, 6); break; + case AVCOL_SPC_SMPTE240M: avio_wb16(pb, 7); break; + case AVCOL_SPC_BT2020_NCL: avio_wb16(pb, 9); break; + default: avio_wb16(pb, 2); } if (track->mode == MODE_MP4) { @@ -1817,6 +1878,13 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr char compressor_name[32] = { 0 }; int avid = 0; + int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422) + || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422) + || track->par->codec_id == AV_CODEC_ID_V308 + || track->par->codec_id == AV_CODEC_ID_V408 + || track->par->codec_id == AV_CODEC_ID_V410 + || track->par->codec_id == AV_CODEC_ID_V210); + avio_wb32(pb, 0); /* size */ if (mov->encryption_scheme != MOV_ENC_NONE) { ffio_wfourcc(pb, "encv"); @@ -1827,11 +1895,15 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr avio_wb16(pb, 0); /* Reserved */ avio_wb16(pb, 1); /* Data-reference index */ - avio_wb16(pb, 0); /* Codec stream version */ + if (uncompressed_ycbcr) { + avio_wb16(pb, 2); /* Codec stream version */ + } else { + avio_wb16(pb, 0); /* Codec stream version */ + } avio_wb16(pb, 0); /* Codec stream revision (=0) */ if (track->mode == MODE_MOV) { ffio_wfourcc(pb, "FFMP"); /* Vendor */ - if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO) { + if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) { avio_wb32(pb, 0); /* Temporal Quality */ avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/ } else { @@ -1855,7 +1927,10 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr avio_w8(pb, strlen(compressor_name)); avio_write(pb, compressor_name, 31); - if (track->mode == MODE_MOV && track->par->bits_per_coded_sample) + if (track->mode == MODE_MOV && + (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210)) + avio_wb16(pb, 0x18); + else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample) avio_wb16(pb, track->par->bits_per_coded_sample | (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0)); else @@ -1955,6 +2030,10 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr mov_write_pasp_tag(pb, track); } + if (uncompressed_ycbcr){ + mov_write_clap_tag(pb, track); + } + if (mov->encryption_scheme != MOV_ENC_NONE) { ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid); } @@ -2305,6 +2384,8 @@ static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext track->par->codec_tag == MKTAG('r','t','p',' ')) && track->has_keyframes && track->has_keyframes < track->entry) mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE); + if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable) + mov_write_sdtp_tag(pb, track); if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS) mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE); if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && @@ -5268,6 +5349,10 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE) trk->has_keyframes++; } + if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) { + trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE; + trk->has_disposable++; + } trk->entry++; trk->sample_count += samples_in_chunk; mov->mdat_size += size; @@ -6498,6 +6583,7 @@ static const AVCodecTag codec_3gp_tags[] = { const AVCodecTag codec_mp4_tags[] = { { AV_CODEC_ID_MPEG4 , MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_H264 , MKTAG('a', 'v', 'c', '1') }, + { AV_CODEC_ID_H264 , MKTAG('a', 'v', 'c', '3') }, { AV_CODEC_ID_HEVC , MKTAG('h', 'e', 'v', '1') }, { AV_CODEC_ID_HEVC , MKTAG('h', 'v', 'c', '1') }, { AV_CODEC_ID_MPEG2VIDEO , MKTAG('m', 'p', '4', 'v') }, @@ -6663,7 +6749,7 @@ AVOutputFormat ff_ipod_muxer = { .name = "ipod", .long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"), .mime_type = "video/mp4", - .extensions = "m4v,m4a", + .extensions = "m4v,m4a,m4b", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_H264, diff --git a/libavformat/movenc.h b/libavformat/movenc.h index cc2a155d7..c4e966b7f 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -53,6 +53,7 @@ typedef struct MOVIentry { int cts; #define MOV_SYNC_SAMPLE 0x0001 #define MOV_PARTIAL_SYNC_SAMPLE 0x0002 +#define MOV_DISPOSABLE_SAMPLE 0x0004 uint32_t flags; } MOVIentry; @@ -89,6 +90,7 @@ typedef struct MOVTrack { long sample_size; long chunkCount; int has_keyframes; + int has_disposable; #define MOV_TRACK_CTTS 0x0001 #define MOV_TRACK_STPS 0x0002 #define MOV_TRACK_ENABLED 0x0004 diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c index a5c4f2ea1..a76fe32e5 100644 --- a/libavformat/mp3dec.c +++ b/libavformat/mp3dec.c @@ -508,9 +508,9 @@ static int64_t mp3_sync(AVFormatContext *s, int64_t target_pos, int flags) return AVERROR(EINVAL); } } - if ((target_pos - pos)*dir <= 0 && abs(MIN_VALID/2-j) < score) { + if ((target_pos - pos)*dir <= 0 && FFABS(MIN_VALID/2-j) < score) { candidate = pos; - score = abs(MIN_VALID/2-j); + score = FFABS(MIN_VALID/2-j); } pos += ret; } diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 53cbcfb54..0a3ad0572 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2296,6 +2296,14 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) } } + if (packet[1] & 0x80) { + av_log(ts->stream, AV_LOG_DEBUG, "Packet had TEI flag set; marking as corrupt\n"); + if (tss->type == MPEGTS_PES) { + PESContext *pc = tss->u.pes_filter.opaque; + pc->flags |= AV_PKT_FLAG_CORRUPT; + } + } + p = packet + 4; if (has_adaptation) { int64_t pcr_h; diff --git a/libavformat/mpjpeg.c b/libavformat/mpjpeg.c index 3904ccb2b..80f83c587 100644 --- a/libavformat/mpjpeg.c +++ b/libavformat/mpjpeg.c @@ -23,7 +23,7 @@ /* Multipart JPEG */ -#define BOUNDARY_TAG "ffserver" +#define BOUNDARY_TAG "ffmpeg" typedef struct MPJPEGContext { AVClass *class; diff --git a/libavformat/mux.c b/libavformat/mux.c index 53ad46df4..ea9f13fdf 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -255,19 +255,10 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) FF_DISABLE_DEPRECATION_WARNINGS if (s->nb_streams && s->streams[0]->codec->flags & AV_CODEC_FLAG_BITEXACT) { if (!(s->flags & AVFMT_FLAG_BITEXACT)) { -#if FF_API_LAVF_BITEXACT - av_log(s, AV_LOG_WARNING, - "Setting the AVFormatContext to bitexact mode, because " - "the AVCodecContext is in that mode. This behavior will " - "change in the future. To keep the current behavior, set " - "AVFormatContext.flags |= AVFMT_FLAG_BITEXACT.\n"); - s->flags |= AVFMT_FLAG_BITEXACT; -#else av_log(s, AV_LOG_WARNING, "The AVFormatContext is not in set to bitexact mode, only " "the AVCodecContext. If this is not intended, set " "AVFormatContext.flags |= AVFMT_FLAG_BITEXACT.\n"); -#endif } } FF_ENABLE_DEPRECATION_WARNINGS @@ -284,17 +275,6 @@ FF_ENABLE_DEPRECATION_WARNINGS st = s->streams[i]; par = st->codecpar; -#if FF_API_LAVF_CODEC_TB && FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if (!st->time_base.num && st->codec->time_base.num) { - av_log(s, AV_LOG_WARNING, "Using AVStream.codec.time_base as a " - "timebase hint to the muxer is deprecated. Set " - "AVStream.time_base instead.\n"); - avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS if (st->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN && @@ -452,19 +432,27 @@ static int init_pts(AVFormatContext *s) break; } - if (!st->priv_pts) - st->priv_pts = av_mallocz(sizeof(*st->priv_pts)); - if (!st->priv_pts) + if (!st->internal->priv_pts) + st->internal->priv_pts = av_mallocz(sizeof(*st->internal->priv_pts)); + if (!st->internal->priv_pts) return AVERROR(ENOMEM); if (den != AV_NOPTS_VALUE) { if (den <= 0) return AVERROR_INVALIDDATA; - frac_init(st->priv_pts, 0, 0, den); + frac_init(st->internal->priv_pts, 0, 0, den); } } + if (s->avoid_negative_ts < 0) { + av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); + if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { + s->avoid_negative_ts = 0; + } else + s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; + } + return 0; } @@ -478,25 +466,6 @@ static void flush_if_needed(AVFormatContext *s) } } -static int write_header_internal(AVFormatContext *s) -{ - if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) - avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER); - if (s->oformat->write_header) { - int ret = s->oformat->write_header(s); - if (ret >= 0 && s->pb && s->pb->error < 0) - ret = s->pb->error; - s->internal->write_header_ret = ret; - if (ret < 0) - return ret; - flush_if_needed(s); - } - s->internal->header_written = 1; - if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) - avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_UNKNOWN); - return 0; -} - int avformat_init_output(AVFormatContext *s, AVDictionary **options) { int ret = 0; @@ -511,14 +480,6 @@ int avformat_init_output(AVFormatContext *s, AVDictionary **options) if ((ret = init_pts(s)) < 0) return ret; - if (s->avoid_negative_ts < 0) { - av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); - if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { - s->avoid_negative_ts = 0; - } else - s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; - } - return AVSTREAM_INIT_IN_INIT_OUTPUT; } @@ -535,23 +496,22 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) if ((ret = avformat_init_output(s, options)) < 0) return ret; - if (!(s->oformat->check_bitstream && s->flags & AVFMT_FLAG_AUTO_BSF)) { - ret = write_header_internal(s); + if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) + avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER); + if (s->oformat->write_header) { + ret = s->oformat->write_header(s); + if (ret >= 0 && s->pb && s->pb->error < 0) + ret = s->pb->error; if (ret < 0) goto fail; + flush_if_needed(s); } + if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) + avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_UNKNOWN); if (!s->internal->streams_initialized) { if ((ret = init_pts(s)) < 0) goto fail; - - if (s->avoid_negative_ts < 0) { - av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); - if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { - s->avoid_negative_ts = 0; - } else - s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; - } } return streams_already_initialized; @@ -621,7 +581,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * } pkt->dts = // pkt->pts= st->cur_dts; - pkt->pts = st->priv_pts->val; + pkt->pts = st->internal->priv_pts->val; } //calculate dts from pts @@ -658,7 +618,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * av_ts2str(pkt->pts), av_ts2str(pkt->dts)); st->cur_dts = pkt->dts; - st->priv_pts->val = pkt->dts; + st->internal->priv_pts->val = pkt->dts; /* update pts */ switch (st->codecpar->codec_type) { @@ -670,12 +630,12 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * /* HACK/FIXME, we skip the initial 0 size packets as they are most * likely equal to the encoder delay, but it would be better if we * had the real timestamps from the encoder */ - if (frame_size >= 0 && (pkt->size || st->priv_pts->num != st->priv_pts->den >> 1 || st->priv_pts->val)) { - frac_add(st->priv_pts, (int64_t)st->time_base.den * frame_size); + if (frame_size >= 0 && (pkt->size || st->internal->priv_pts->num != st->internal->priv_pts->den >> 1 || st->internal->priv_pts->val)) { + frac_add(st->internal->priv_pts, (int64_t)st->time_base.den * frame_size); } break; case AVMEDIA_TYPE_VIDEO: - frac_add(st->priv_pts, (int64_t)st->time_base.den * st->time_base.num); + frac_add(st->internal->priv_pts, (int64_t)st->time_base.den * st->time_base.num); break; } return 0; @@ -694,7 +654,7 @@ FF_ENABLE_DEPRECATION_WARNINGS */ static int write_packet(AVFormatContext *s, AVPacket *pkt) { - int ret, did_split; + int ret; int64_t pts_backup, dts_backup; pts_backup = pkt->pts; @@ -759,18 +719,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) } } -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - did_split = av_packet_split_side_data(pkt); -FF_ENABLE_DEPRECATION_WARNINGS -#endif - - if (!s->internal->header_written) { - ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s); - if (ret < 0) - goto fail; - } - if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { AVFrame *frame = (AVFrame *)pkt->data; av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); @@ -786,14 +734,6 @@ FF_ENABLE_DEPRECATION_WARNINGS ret = s->pb->error; } -fail: -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - if (did_split) - av_packet_merge_side_data(pkt); -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (ret < 0) { pkt->pts = pts_backup; pkt->dts = dts_backup; @@ -889,16 +829,6 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { } } -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - if (st->internal->nb_bsfcs) { - ret = av_packet_split_side_data(pkt); - if (ret < 0) - av_log(s, AV_LOG_WARNING, "Failed to split side data before bitstream filter\n"); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - for (i = 0; i < st->internal->nb_bsfcs; i++) { AVBSFContext *ctx = st->internal->bsfcs[i]; // TODO: when any bitstream filter requires flushing at EOF, we'll need to @@ -918,7 +848,9 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(ctx, AV_LOG_ERROR, "Failed to send packet to filter %s for stream %d\n", ctx->filter->name, pkt->stream_index); - return ret; + if (s->error_recognition & AV_EF_EXPLODE) + return ret; + return 0; } } return 1; @@ -934,11 +866,6 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) if (!pkt) { if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { - if (!s->internal->header_written) { - ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s); - if (ret < 0) - return ret; - } ret = s->oformat->write_packet(s, NULL); flush_if_needed(s); if (ret >= 0 && s->pb && s->pb->error < 0) @@ -1322,14 +1249,8 @@ int av_write_trailer(AVFormatContext *s) goto fail; } - if (!s->internal->header_written) { - ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s); - if (ret < 0) - goto fail; - } - fail: - if (s->internal->header_written && s->oformat->write_trailer) { + if (s->oformat->write_trailer) { if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER); if (ret >= 0) { @@ -1342,7 +1263,6 @@ fail: if (s->oformat->deinit) s->oformat->deinit(s); - s->internal->header_written = s->internal->initialized = s->internal->streams_initialized = 0; diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c index f7aa4cbae..fa596179e 100644 --- a/libavformat/mvdec.c +++ b/libavformat/mvdec.c @@ -227,7 +227,9 @@ static int read_table(AVFormatContext *avctx, AVStream *st, int (*parse)(AVFormatContext *avctx, AVStream *st, const char *name, int size)) { - int count, i; + unsigned count; + int i; + AVIOContext *pb = avctx->pb; avio_skip(pb, 4); count = avio_rb32(pb); @@ -235,6 +237,10 @@ static int read_table(AVFormatContext *avctx, AVStream *st, for (i = 0; i < count; i++) { char name[17]; int size; + + if (avio_feof(pb)) + return AVERROR_EOF; + avio_read(pb, name, 16); name[sizeof(name) - 1] = 0; size = avio_rb32(pb); diff --git a/libavformat/mxf.c b/libavformat/mxf.c index bfc3218b8..a909401f0 100644 --- a/libavformat/mxf.c +++ b/libavformat/mxf.c @@ -137,6 +137,7 @@ static const MXFSamplesPerFrame mxf_spf[] = { { { 1001, 60000 }, { 801, 801, 801, 801, 800, 0 } }, // NTSC 59.94 { { 1, 25 }, { 1920, 0, 0, 0, 0, 0 } }, // PAL 25 { { 1, 50 }, { 960, 0, 0, 0, 0, 0 } }, // PAL 50 + { { 1, 60 }, { 800, 0, 0, 0, 0, 0 } }, }; static const AVRational mxf_time_base[] = { @@ -146,6 +147,7 @@ static const AVRational mxf_time_base[] = { { 1001, 60000 }, { 1, 25 }, { 1, 50 }, + { 1, 60 }, { 0, 0} }; @@ -155,7 +157,7 @@ const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, int idx = av_find_nearest_q_idx(time_base, mxf_time_base); AVRational diff = av_sub_q(time_base, mxf_time_base[idx]); - diff.num = abs(diff.num); + diff.num = FFABS(diff.num); if (av_cmp_q(diff, (AVRational){1, 1000}) >= 0) return NULL; diff --git a/libavformat/mxf.h b/libavformat/mxf.h index f3db1f939..ffcc429a8 100644 --- a/libavformat/mxf.h +++ b/libavformat/mxf.h @@ -45,9 +45,9 @@ enum MXFMetadataSetType { SubDescriptor, IndexTableSegment, EssenceContainerData, - TypeBottom,// add metadata type before this EssenceGroup, TaggedValue, + TapeDescriptor, }; enum MXFFrameLayout { diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 118e3e40b..3b8d42390 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -2976,7 +2976,7 @@ static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset /* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */ while (mxf->current_edit_unit >= 0) { if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) - return -1; + return -2; if (next_ofs <= last_ofs) { /* large next_ofs didn't change or current_edit_unit wrapped @@ -3065,7 +3065,7 @@ static int mxf_set_pts(MXFContext *mxf, AVStream *st, AVPacket *pkt, int64_t nex AVCodecParameters *par = st->codecpar; MXFTrack *track = st->priv_data; - if (par->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) { + if (par->codec_type == AVMEDIA_TYPE_VIDEO && (next_ofs >= 0 || next_ofs == -2 && st->duration == mxf->current_edit_unit + 1)) { /* mxf->current_edit_unit good - see if we have an * index table to derive timestamps from */ MXFIndexTable *t = &mxf->index_tables[0]; diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 035e65ed4..3bb70326f 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -101,6 +101,13 @@ typedef struct MXFContainerEssenceEntry { void (*write_desc)(AVFormatContext *, AVStream *); } MXFContainerEssenceEntry; +typedef struct MXFPackage { + char *name; + enum MXFMetadataSetType type; + int instance; + struct MXFPackage *ref; +} MXFPackage; + enum ULIndex { INDEX_MPEG2 = 0, INDEX_AES3, @@ -380,6 +387,7 @@ typedef struct MXFContext { uint32_t tagged_value_count; AVRational audio_edit_rate; int store_user_comments; + int track_instance_count; // used to generate MXFTrack uuids } MXFContext; static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; @@ -808,13 +816,14 @@ static void mxf_write_identification(AVFormatContext *s) avio_wb64(pb, mxf->timestamp); } -static void mxf_write_content_storage(AVFormatContext *s) +static void mxf_write_content_storage(AVFormatContext *s, MXFPackage *packages, int package_count) { AVIOContext *pb = s->pb; + int i; mxf_write_metadata_key(pb, 0x011800); PRINT_KEY(s, "content storage key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 92); + klv_encode_ber_length(pb, 60 + (16 * package_count)); // write uid mxf_write_local_tag(pb, 16, 0x3C0A); @@ -822,10 +831,11 @@ static void mxf_write_content_storage(AVFormatContext *s) PRINT_KEY(s, "content storage uid", pb->buf_ptr - 16); // write package reference - mxf_write_local_tag(pb, 16 * 2 + 8, 0x1901); - mxf_write_refs_count(pb, 2); - mxf_write_uuid(pb, MaterialPackage, 0); - mxf_write_uuid(pb, SourcePackage, 0); + mxf_write_local_tag(pb, 16 * package_count + 8, 0x1901); + mxf_write_refs_count(pb, package_count); + for (i = 0; i < package_count; i++) { + mxf_write_uuid(pb, packages[i].type, packages[i].instance); + } // write essence container data mxf_write_local_tag(pb, 8 + 16, 0x1902); @@ -833,7 +843,7 @@ static void mxf_write_content_storage(AVFormatContext *s) mxf_write_uuid(pb, EssenceContainerData, 0); } -static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_track(AVFormatContext *s, AVStream *st, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; @@ -845,7 +855,7 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe // write track uid mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, st->index); + mxf_write_uuid(pb, Track, mxf->track_instance_count); PRINT_KEY(s, "track uid", pb->buf_ptr - 16); // write track id @@ -854,7 +864,7 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe // write track number mxf_write_local_tag(pb, 4, 0x4804); - if (type == MaterialPackage) + if (package->type == MaterialPackage) avio_wb32(pb, 0); // track number of material package is 0 else avio_write(pb, sc->track_essence_element_key + 12, 4); @@ -876,7 +886,7 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe // write sequence refs mxf_write_local_tag(pb, 16, 0x4803); - mxf_write_uuid(pb, type == MaterialPackage ? Sequence: Sequence + TypeBottom, st->index); + mxf_write_uuid(pb, Sequence, mxf->track_instance_count); } static const uint8_t smpte_12m_timecode_track_data_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x01,0x01,0x00,0x00,0x00 }; @@ -905,7 +915,7 @@ static void mxf_write_common_fields(AVFormatContext *s, AVStream *st) } } -static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_sequence(AVFormatContext *s, AVStream *st, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; @@ -916,7 +926,7 @@ static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadat klv_encode_ber_length(pb, 80); mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? Sequence: Sequence + TypeBottom, st->index); + mxf_write_uuid(pb, Sequence, mxf->track_instance_count); PRINT_KEY(s, "sequence uid", pb->buf_ptr - 16); mxf_write_common_fields(s, st); @@ -928,12 +938,11 @@ static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadat component = TimecodeComponent; else component = SourceClip; - if (type == SourcePackage) - component += TypeBottom; - mxf_write_uuid(pb, component, st->index); + + mxf_write_uuid(pb, component, mxf->track_instance_count); } -static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; @@ -943,8 +952,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum // UID mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? TimecodeComponent : - TimecodeComponent + TypeBottom, st->index); + mxf_write_uuid(pb, TimecodeComponent, mxf->track_instance_count); mxf_write_common_fields(s, st); @@ -961,8 +969,9 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum avio_w8(pb, !!(mxf->tc.flags & AV_TIMECODE_FLAG_DROPFRAME)); } -static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, MXFPackage *package) { + MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; int i; @@ -972,7 +981,7 @@ static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enu // write uid mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? SourceClip: SourceClip + TypeBottom, st->index); + mxf_write_uuid(pb, SourceClip, mxf->track_instance_count); PRINT_KEY(s, "structural component uid", pb->buf_ptr - 16); mxf_write_common_fields(s, st); @@ -983,20 +992,33 @@ static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enu // write source package uid, end of the reference mxf_write_local_tag(pb, 32, 0x1101); - if (type == SourcePackage) { + if (!package->ref) { for (i = 0; i < 4; i++) avio_wb64(pb, 0); } else - mxf_write_umid(s, 1); + mxf_write_umid(s, package->ref->instance); // write source track id mxf_write_local_tag(pb, 4, 0x1102); - if (type == SourcePackage) + if (package->type == SourcePackage && !package->ref) avio_wb32(pb, 0); else avio_wb32(pb, st->index+2); } +static void mxf_write_tape_descriptor(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + + mxf_write_metadata_key(pb, 0x012e00); + PRINT_KEY(s, "tape descriptor key", pb->buf_ptr - 16); + klv_encode_ber_length(pb, 20); + mxf_write_local_tag(pb, 16, 0x3C0A); + mxf_write_uuid(pb, TapeDescriptor, 0); + PRINT_KEY(s, "tape_desc uid", pb->buf_ptr - 16); +} + + static void mxf_write_multi_descriptor(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -1321,15 +1343,15 @@ static int mxf_write_user_comments(AVFormatContext *s, const AVDictionary *m) return count; } -static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, const char *package_name) +static void mxf_write_package(AVFormatContext *s, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; int i, track_count = s->nb_streams+1; - int name_size = mxf_utf16_local_tag_length(package_name); + int name_size = mxf_utf16_local_tag_length(package->name); int user_comment_count = 0; - if (type == MaterialPackage) { + if (package->type == MaterialPackage) { if (mxf->store_user_comments) user_comment_count = mxf_write_user_comments(s, s->metadata); mxf_write_metadata_key(pb, 0x013600); @@ -1343,18 +1365,18 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, // write uid mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type, 0); - av_log(s, AV_LOG_DEBUG, "package type:%d\n", type); + mxf_write_uuid(pb, package->type, package->instance); + av_log(s, AV_LOG_DEBUG, "package type:%d\n", package->type); PRINT_KEY(s, "package uid", pb->buf_ptr - 16); // write package umid mxf_write_local_tag(pb, 32, 0x4401); - mxf_write_umid(s, type == SourcePackage); + mxf_write_umid(s, package->instance); PRINT_KEY(s, "package umid second part", pb->buf_ptr - 16); // package name if (name_size) - mxf_write_local_tag_utf16(pb, 0x4402, package_name); + mxf_write_local_tag_utf16(pb, 0x4402, package->name); // package creation date mxf_write_local_tag(pb, 8, 0x4405); @@ -1367,10 +1389,9 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, // write track refs mxf_write_local_tag(pb, track_count*16 + 8, 0x4403); mxf_write_refs_count(pb, track_count); - mxf_write_uuid(pb, type == MaterialPackage ? Track : - Track + TypeBottom, -1); // timecode track - for (i = 0; i < s->nb_streams; i++) - mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, i); + // these are the uuids of the tracks the will be written in mxf_write_track + for (i = 0; i < track_count; i++) + mxf_write_uuid(pb, Track, mxf->track_instance_count + i); // write user comment refs if (mxf->store_user_comments) { @@ -1381,27 +1402,41 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, } // write multiple descriptor reference - if (type == SourcePackage) { + if (package->type == SourcePackage && package->instance == 1) { mxf_write_local_tag(pb, 16, 0x4701); if (s->nb_streams > 1) { mxf_write_uuid(pb, MultipleDescriptor, 0); mxf_write_multi_descriptor(s); } else mxf_write_uuid(pb, SubDescriptor, 0); + } else if (package->type == SourcePackage && package->instance == 2) { + mxf_write_local_tag(pb, 16, 0x4701); + mxf_write_uuid(pb, TapeDescriptor, 0); + mxf_write_tape_descriptor(s); } + /* + * for every 1 track in a package there is 1 sequence and 1 component. + * all 3 of these elements share the same instance number for generating + * there instance uuids. mxf->track_instance_count stores this value. + * mxf->track_instance_count is incremented after a group of all 3 of + * these elements are written. + */ + // write timecode track - mxf_write_track(s, mxf->timecode_track, type); - mxf_write_sequence(s, mxf->timecode_track, type); - mxf_write_timecode_component(s, mxf->timecode_track, type); + mxf_write_track(s, mxf->timecode_track, package); + mxf_write_sequence(s, mxf->timecode_track, package); + mxf_write_timecode_component(s, mxf->timecode_track, package); + mxf->track_instance_count++; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - mxf_write_track(s, st, type); - mxf_write_sequence(s, st, type); - mxf_write_structural_component(s, st, type); + mxf_write_track(s, st, package); + mxf_write_sequence(s, st, package); + mxf_write_structural_component(s, st, package); + mxf->track_instance_count++; - if (type == SourcePackage) { + if (package->type == SourcePackage && package->instance == 1) { MXFStreamContext *sc = st->priv_data; mxf_essence_container_uls[sc->index].write_desc(s, st); } @@ -1432,33 +1467,49 @@ static int mxf_write_essence_container_data(AVFormatContext *s) static int mxf_write_header_metadata_sets(AVFormatContext *s) { - const char *material_package_name = NULL; - const char *file_package_name = NULL; + MXFContext *mxf = s->priv_data; AVDictionaryEntry *entry = NULL; AVStream *st = NULL; int i; + MXFPackage packages[3] = {{0}}; + int package_count = 2; + packages[0].type = MaterialPackage; + packages[1].type = SourcePackage; + packages[1].instance = 1; + packages[0].ref = &packages[1]; + if (entry = av_dict_get(s->metadata, "material_package_name", NULL, 0)) - material_package_name = entry->value; + packages[0].name = entry->value; if (entry = av_dict_get(s->metadata, "file_package_name", NULL, 0)) { - file_package_name = entry->value; + packages[1].name = entry->value; } else { /* check if any of the streams contain a file_package_name */ for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (entry = av_dict_get(st->metadata, "file_package_name", NULL, 0)) { - file_package_name = entry->value; + packages[1].name = entry->value; break; } } } + entry = av_dict_get(s->metadata, "reel_name", NULL, 0); + if (entry) { + packages[2].name = entry->value; + packages[2].type = SourcePackage; + packages[2].instance = 2; + packages[1].ref = &packages[2]; + package_count = 3; + } + mxf_write_preface(s); mxf_write_identification(s); - mxf_write_content_storage(s); - mxf_write_package(s, MaterialPackage, material_package_name); - mxf_write_package(s, SourcePackage, file_package_name); + mxf_write_content_storage(s, packages, package_count); + mxf->track_instance_count = 0; + for (i = 0; i < package_count; i++) + mxf_write_package(s, &packages[i]); mxf_write_essence_container_data(s); return 0; } diff --git a/libavformat/network.c b/libavformat/network.c index b3987a4d1..e9eb4b443 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -29,25 +29,29 @@ int ff_tls_init(void) { -#if CONFIG_TLS_OPENSSL_PROTOCOL +#if CONFIG_TLS_PROTOCOL +#if CONFIG_OPENSSL int ret; if ((ret = ff_openssl_init()) < 0) return ret; #endif -#if CONFIG_TLS_GNUTLS_PROTOCOL +#if CONFIG_GNUTLS ff_gnutls_init(); +#endif #endif return 0; } void ff_tls_deinit(void) { -#if CONFIG_TLS_OPENSSL_PROTOCOL +#if CONFIG_TLS_PROTOCOL +#if CONFIG_OPENSSL ff_openssl_deinit(); #endif -#if CONFIG_TLS_GNUTLS_PROTOCOL +#if CONFIG_GNUTLS ff_gnutls_deinit(); #endif +#endif } int ff_network_inited_globally; @@ -99,6 +103,24 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt } } +int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb) +{ + int64_t wait_start = av_gettime_relative(); + + while (1) { + int64_t time_left; + + if (ff_check_interrupt(int_cb)) + return AVERROR_EXIT; + + time_left = timeout - (av_gettime_relative() - wait_start); + if (time_left <= 0) + return AVERROR(ETIMEDOUT); + + av_usleep(FFMIN(time_left, POLLING_TIME * 1000)); + } +} + void ff_network_close(void) { #if HAVE_WINSOCK2_H diff --git a/libavformat/network.h b/libavformat/network.h index f83c796a9..3c0f87327 100644 --- a/libavformat/network.h +++ b/libavformat/network.h @@ -59,6 +59,7 @@ int ff_neterrno(void); #include #include #include +#include #include #define ff_neterrno() AVERROR(errno) @@ -95,7 +96,14 @@ int ff_network_wait_fd(int fd, int write); */ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb); -int ff_inet_aton (const char * str, struct in_addr * add); +/** + * Waits for up to 'timeout' microseconds. If the usert's int_cb is set and + * triggered, return before that. + * @timeout Timeout in microseconds. Maybe have lower actual precision. + * @param int_cb Interrupt callback, is checked regularly. + * @return AVERROR(ETIMEDOUT) if timeout expirted, AVERROR_EXIT if interrupted by int_cb + */ +int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb); #if !HAVE_STRUCT_SOCKADDR_STORAGE struct sockaddr_storage { diff --git a/libavformat/nspdec.c b/libavformat/nspdec.c new file mode 100644 index 000000000..34c747b65 --- /dev/null +++ b/libavformat/nspdec.c @@ -0,0 +1,108 @@ +/* + * NSP demuxer + * 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 "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "pcm.h" + +static int nsp_probe(AVProbeData *p) +{ + if (AV_RB32(p->buf) == AV_RB32("FORM") && + AV_RB32(p->buf + 4) == AV_RB32("DS16")) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int nsp_read_header(AVFormatContext *s) +{ + int channels = 0, rate = 0; + uint32_t chunk, size; + AVStream *st; + int64_t pos; + + avio_skip(s->pb, 12); + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + while (!avio_feof(s->pb)) { + char value[1024]; + + chunk = avio_rb32(s->pb); + size = avio_rl32(s->pb); + pos = avio_tell(s->pb); + + switch (chunk) { + case MKBETAG('H', 'E', 'D', 'R'): + case MKBETAG('H', 'D', 'R', '8'): + if (size < 32) + return AVERROR_INVALIDDATA; + avio_skip(s->pb, 20); + rate = avio_rl32(s->pb); + avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); + break; + case MKBETAG('N', 'O', 'T', 'E'): + avio_get_str(s->pb, size, value, sizeof(value)); + av_dict_set(&s->metadata, "Comment", value, 0); + avio_skip(s->pb, size & 1); + break; + case MKBETAG('S', 'D', 'A', 'B'): + channels = 2; + break; + case MKBETAG('S', 'D', '_', '2'): + case MKBETAG('S', 'D', '_', '3'): + case MKBETAG('S', 'D', '_', '4'): + case MKBETAG('S', 'D', '_', '5'): + case MKBETAG('S', 'D', '_', '6'): + case MKBETAG('S', 'D', '_', '7'): + case MKBETAG('S', 'D', '_', '8'): + av_log(s, AV_LOG_WARNING, "Unsupported chunk!\n"); + case MKBETAG('S', 'D', 'A', '_'): + case MKBETAG('S', 'D', '_', 'A'): + channels = 1; + break; + } + + if (channels) + break; + } + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->channels = channels; + st->codecpar->sample_rate = rate; + st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codecpar->block_align = 2 * channels; + + return 0; +} + +AVInputFormat ff_nsp_demuxer = { + .name = "nsp", + .long_name = NULL_IF_CONFIG_SMALL("Computerized Speech Lab NSP"), + .read_probe = nsp_probe, + .read_header = nsp_read_header, + .read_packet = ff_pcm_read_packet, + .read_seek = ff_pcm_read_seek, + .extensions = "nsp", + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 97ad1a27d..38f60653f 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -543,7 +543,11 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, os->incomplete = 0; if (os->header) { - os->header = os->codec->header(s, idx); + if ((ret = os->codec->header(s, idx)) < 0) { + av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret)); + return ret; + } + os->header = ret; if (!os->header) { os->segp = segp; os->psize = psize; @@ -574,8 +578,12 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, } else { os->pflags = 0; os->pduration = 0; - if (os->codec && os->codec->packet) - os->codec->packet(s, idx); + if (os->codec && os->codec->packet) { + if ((ret = os->codec->packet(s, idx)) < 0) { + av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret)); + return ret; + } + } if (sid) *sid = idx; if (dstart) @@ -719,8 +727,10 @@ static int ogg_read_header(AVFormatContext *s) "Headers mismatch for stream %d: " "expected %d received %d.\n", i, os->codec->nb_header, os->nb_header); - if (s->error_recognition & AV_EF_EXPLODE) + if (s->error_recognition & AV_EF_EXPLODE) { + ogg_read_close(s); return AVERROR_INVALIDDATA; + } } if (os->start_granule != OGG_NOGRANULE_VALUE) os->lastpts = s->streams[i]->start_time = diff --git a/libavformat/oggparseogm.c b/libavformat/oggparseogm.c index e7a501b5a..ca6b62669 100644 --- a/libavformat/oggparseogm.c +++ b/libavformat/oggparseogm.c @@ -24,7 +24,6 @@ #include -#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavcodec/bytestream.h" @@ -106,10 +105,10 @@ ogm_header(AVFormatContext *s, int idx) size -= 4; } if (size > 52) { - av_assert0(AV_INPUT_BUFFER_PADDING_SIZE <= 52); size -= 52; if (bytestream2_get_bytes_left(&p) < size) return AVERROR_INVALIDDATA; + av_freep(&st->codecpar->extradata); if (ff_alloc_extradata(st->codecpar, size) < 0) return AVERROR(ENOMEM); bytestream2_get_buffer(&p, st->codecpar->extradata, st->codecpar->extradata_size); diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c index f45ad8487..cd34cf23b 100644 --- a/libavformat/oggparseopus.c +++ b/libavformat/oggparseopus.c @@ -62,6 +62,7 @@ static int opus_header(AVFormatContext *avf, int idx) /*gain = AV_RL16(packet + 16);*/ /*channel_map = AV_RL8 (packet + 18);*/ + av_freep(&st->codecpar->extradata); if (ff_alloc_extradata(st->codecpar, os->psize)) return AVERROR(ENOMEM); diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 65b1998a0..29b1ab514 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -317,7 +317,7 @@ static int vorbis_header(AVFormatContext *s, int idx) if (priv->packet[pkt_type >> 1]) return AVERROR_INVALIDDATA; if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) - return AVERROR_INVALIDDATA; + return priv->vp ? 0 : AVERROR_INVALIDDATA; priv->len[pkt_type >> 1] = os->psize; priv->packet[pkt_type >> 1] = av_mallocz(os->psize); diff --git a/libavformat/oggparsevp8.c b/libavformat/oggparsevp8.c index c534ab117..b76ac71cc 100644 --- a/libavformat/oggparsevp8.c +++ b/libavformat/oggparsevp8.c @@ -125,7 +125,7 @@ static int vp8_packet(AVFormatContext *s, int idx) os->lastdts = vp8_gptopts(s, idx, os->granule, NULL) - duration; if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = os->lastpts; - if (s->streams[idx]->duration) + if (s->streams[idx]->duration && s->streams[idx]->duration != AV_NOPTS_VALUE) s->streams[idx]->duration -= s->streams[idx]->start_time; } } diff --git a/libavformat/options_table.h b/libavformat/options_table.h index 118086df6..b8fa47c6f 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -49,7 +49,7 @@ static const AVOption avformat_options[] = { {"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"}, {"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"}, #if FF_API_LAVF_KEEPSIDE_FLAG -{"keepside", "don't merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, +{"keepside", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, #endif {"fastseek", "fast but inaccurate seeks", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FAST_SEEK }, INT_MIN, INT_MAX, D, "fflags"}, {"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, @@ -57,7 +57,7 @@ static const AVOption avformat_options[] = { {"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D}, {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, {"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" }, -{"autobsf", "add needed bsfs automatically (delays header until each stream's first packet is written)", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_AUTO_BSF }, 0, 0, E, "fflags" }, +{"autobsf", "add needed bsfs automatically", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_AUTO_BSF }, 0, 0, E, "fflags" }, {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 86d0b8f30..099d7b501 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -46,7 +46,7 @@ #if !HAVE_INET_ATON #include -int ff_inet_aton(const char *str, struct in_addr *add) +static int inet_aton(const char *str, struct in_addr *add) { unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0; @@ -60,11 +60,6 @@ int ff_inet_aton(const char *str, struct in_addr *add) return 1; } -#else -int ff_inet_aton(const char *str, struct in_addr *add) -{ - return inet_aton(str, add); -} #endif /* !HAVE_INET_ATON */ #if !HAVE_GETADDRINFO @@ -75,16 +70,6 @@ int ff_getaddrinfo(const char *node, const char *service, struct addrinfo *ai; struct sockaddr_in *sin; -#if HAVE_WINSOCK2_H - int (WSAAPI *win_getaddrinfo)(const char *node, const char *service, - const struct addrinfo *hints, - struct addrinfo **res); - HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); - win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo"); - if (win_getaddrinfo) - return win_getaddrinfo(node, service, hints, res); -#endif /* HAVE_WINSOCK2_H */ - *res = NULL; sin = av_mallocz(sizeof(struct sockaddr_in)); if (!sin) @@ -92,7 +77,7 @@ int ff_getaddrinfo(const char *node, const char *service, sin->sin_family = AF_INET; if (node) { - if (!ff_inet_aton(node, &sin->sin_addr)) { + if (!inet_aton(node, &sin->sin_addr)) { if (hints && (hints->ai_flags & AI_NUMERICHOST)) { av_free(sin); return EAI_FAIL; @@ -148,17 +133,6 @@ int ff_getaddrinfo(const char *node, const char *service, void ff_freeaddrinfo(struct addrinfo *res) { -#if HAVE_WINSOCK2_H - void (WSAAPI *win_freeaddrinfo)(struct addrinfo *res); - HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); - win_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *res)) - GetProcAddress(ws2mod, "freeaddrinfo"); - if (win_freeaddrinfo) { - win_freeaddrinfo(res); - return; - } -#endif /* HAVE_WINSOCK2_H */ - av_freep(&res->ai_canonname); av_freep(&res->ai_addr); av_freep(&res); @@ -170,16 +144,6 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen, { const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; -#if HAVE_WINSOCK2_H - int (WSAAPI *win_getnameinfo)(const struct sockaddr *sa, socklen_t salen, - char *host, DWORD hostlen, - char *serv, DWORD servlen, int flags); - HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); - win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo"); - if (win_getnameinfo) - return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); -#endif /* HAVE_WINSOCK2_H */ - if (sa->sa_family != AF_INET) return EAI_FAMILY; if (!host && !serv) diff --git a/libavformat/os_support.h b/libavformat/os_support.h index 91220e971..7a56dc9a7 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -40,7 +40,7 @@ #endif #endif -#if defined(_WIN32) && !defined(__MINGW32CE__) +#ifdef _WIN32 # include # ifdef lseek # undef lseek @@ -54,7 +54,7 @@ # undef fstat # endif # define fstat(f,s) _fstati64((f), (s)) -#endif /* defined(_WIN32) && !defined(__MINGW32CE__) */ +#endif /* defined(_WIN32) */ #ifdef __ANDROID__ @@ -139,9 +139,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout); #endif /* HAVE_POLL_H */ #endif /* CONFIG_NETWORK */ -#if defined(__MINGW32CE__) -#define mkdir(a, b) _mkdir(a) -#elif defined(_WIN32) +#ifdef _WIN32 #include #include #include "libavutil/wchar_filename.h" @@ -220,7 +218,7 @@ static inline int win32_rename(const char *src_utf8, const char *dest_utf8) fallback: /* filename may be be in CP_ACP */ -#if !HAVE_WINRT +#if !HAVE_UWP ret = MoveFileExA(src_utf8, dest_utf8, MOVEFILE_REPLACE_EXISTING); if (ret) errno = EPERM; diff --git a/libavformat/protocols.c b/libavformat/protocols.c index 8d3555ed5..669d74d5a 100644 --- a/libavformat/protocols.c +++ b/libavformat/protocols.c @@ -56,10 +56,7 @@ 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_gnutls_protocol; -extern const URLProtocol ff_tls_schannel_protocol; -extern const URLProtocol ff_tls_securetransport_protocol; -extern const URLProtocol ff_tls_openssl_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; diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c index f640121cb..aa3ef76fb 100644 --- a/libavformat/rawenc.c +++ b/libavformat/rawenc.c @@ -91,6 +91,19 @@ AVOutputFormat ff_adx_muxer = { }; #endif +#if CONFIG_APTX_MUXER +AVOutputFormat ff_aptx_muxer = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("raw aptX (Audio Processing Technology for Bluetooth)"), + .extensions = "aptx", + .audio_codec = AV_CODEC_ID_APTX, + .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_CAVSVIDEO_MUXER AVOutputFormat ff_cavsvideo_muxer = { .name = "cavsvideo", diff --git a/libavformat/riff.c b/libavformat/riff.c index 3f0b39077..89117250d 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -404,6 +404,12 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'Y', '2') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'A') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'G') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'Y', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'H', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'Y', '4') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'H', '4') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'R', 'A') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'R', 'G') }, { AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index d6d7d9cd8..fea71a2fc 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -950,12 +950,14 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, } else return -1; } else { - if ((ret = av_get_packet(pb, pkt, len)) < 0) + ret = av_get_packet(pb, pkt, len); + if (ret < 0) return ret; rm_ac3_swap_bytes(st, pkt); } } else { - if ((ret = av_get_packet(pb, pkt, len)) < 0) + ret = av_get_packet(pb, pkt, len); + if (ret < 0) return ret; } @@ -973,16 +975,17 @@ ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb, AVStream *st, RMStream *ast, AVPacket *pkt) { RMDemuxContext *rm = s->priv_data; + int ret; av_assert0 (rm->audio_pkt_cnt > 0); if (ast->deint_id == DEINT_ID_VBRF || ast->deint_id == DEINT_ID_VBRS) { - int ret = av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); + ret = av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); if (ret < 0) return ret; } else { - int ret = av_new_packet(pkt, st->codecpar->block_align); + ret = av_new_packet(pkt, st->codecpar->block_align); if (ret < 0) return ret; memcpy(pkt->data, ast->pkt.data + st->codecpar->block_align * //FIXME avoid this diff --git a/libavformat/rtmpdigest.c b/libavformat/rtmpdigest.c new file mode 100644 index 000000000..a9b1177ed --- /dev/null +++ b/libavformat/rtmpdigest.c @@ -0,0 +1,67 @@ +/* + * RTMP network protocol + * Copyright (c) 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 + * RTMP protocol digest + */ + +#include + +#include "libavutil/error.h" +#include "libavutil/hmac.h" + +#include "rtmp.h" + +int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap, + const uint8_t *key, int keylen, uint8_t *dst) +{ + AVHMAC *hmac; + + hmac = av_hmac_alloc(AV_HMAC_SHA256); + if (!hmac) + return AVERROR(ENOMEM); + + av_hmac_init(hmac, key, keylen); + if (gap <= 0) { + av_hmac_update(hmac, src, len); + } else { //skip 32 bytes used for storing digest + av_hmac_update(hmac, src, gap); + av_hmac_update(hmac, src + gap + 32, len - gap - 32); + } + av_hmac_final(hmac, dst, 32); + + av_hmac_free(hmac); + + return 0; +} + +int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val, + int add_val) +{ + int i, digest_pos = 0; + + for (i = 0; i < 4; i++) + digest_pos += buf[i + off]; + digest_pos = digest_pos % mod_val + add_val; + + return digest_pos; +} diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 7320b4f02..faf2a6f24 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -27,7 +27,6 @@ #include "libavcodec/bytestream.h" #include "libavutil/avstring.h" #include "libavutil/base64.h" -#include "libavutil/hmac.h" #include "libavutil/intfloat.h" #include "libavutil/lfg.h" #include "libavutil/md5.h" @@ -989,41 +988,6 @@ static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt, return rtmp_send_packet(rt, &pkt, 1); } -int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap, - const uint8_t *key, int keylen, uint8_t *dst) -{ - AVHMAC *hmac; - - hmac = av_hmac_alloc(AV_HMAC_SHA256); - if (!hmac) - return AVERROR(ENOMEM); - - av_hmac_init(hmac, key, keylen); - if (gap <= 0) { - av_hmac_update(hmac, src, len); - } else { //skip 32 bytes used for storing digest - av_hmac_update(hmac, src, gap); - av_hmac_update(hmac, src + gap + 32, len - gap - 32); - } - av_hmac_final(hmac, dst, 32); - - av_hmac_free(hmac); - - return 0; -} - -int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val, - int add_val) -{ - int i, digest_pos = 0; - - for (i = 0; i < 4; i++) - digest_pos += buf[i + off]; - digest_pos = digest_pos % mod_val + add_val; - - return digest_pos; -} - /** * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest * will be stored) into that packet. diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index 2c09fda10..09f214a71 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -139,12 +139,12 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p) ret = avformat_open_input(&rt->asf_ctx, "", iformat, &opts); av_dict_free(&opts); if (ret < 0) { - av_free(buf); + av_free(pb.buffer); return ret; } av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0); rt->asf_pb_pos = avio_tell(&pb); - av_free(buf); + av_free(pb.buffer); rt->asf_ctx->pb = NULL; } return ret; diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index 573593fa6..63047becc 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -66,6 +66,7 @@ static int is_supported(enum AVCodecID id) case AV_CODEC_ID_PCM_S8: case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S24BE: case AV_CODEC_ID_PCM_U16BE: case AV_CODEC_ID_PCM_U16LE: case AV_CODEC_ID_PCM_U8: @@ -544,6 +545,8 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_S16LE: return rtp_send_samples(s1, pkt->data, size, 16 * st->codecpar->channels); + case AV_CODEC_ID_PCM_S24BE: + return rtp_send_samples(s1, pkt->data, size, 24 * st->codecpar->channels); case AV_CODEC_ID_ADPCM_G722: /* The actual sample size is half a byte per sample, but since the * stream clock rate is 8000 Hz while the sample rate is 16000 Hz, diff --git a/libavformat/rtpenc_mpegts.c b/libavformat/rtpenc_mpegts.c index 7af02e0d2..5f81e1a14 100644 --- a/libavformat/rtpenc_mpegts.c +++ b/libavformat/rtpenc_mpegts.c @@ -85,6 +85,10 @@ static int rtp_mpegts_write_header(AVFormatContext *s) } rtp_ctx->oformat = rtp_format; st = avformat_new_stream(rtp_ctx, NULL); + if (!st) { + ret = AVERROR(ENOMEM); + goto fail; + } st->time_base.num = 1; st->time_base.den = 90000; st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS; diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index 0706cae25..c01d9cea1 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -636,12 +636,6 @@ int ff_rtp_get_local_rtp_port(URLContext *h) * @return the local port number */ -int ff_rtp_get_local_rtcp_port(URLContext *h) -{ - RTPContext *s = h->priv_data; - return ff_udp_get_local_port(s->rtcp_hd); -} - static int rtp_get_file_handle(URLContext *h) { RTPContext *s = h->priv_data; diff --git a/libavformat/rtpproto.h b/libavformat/rtpproto.h index 5b243fb24..131aac5f3 100644 --- a/libavformat/rtpproto.h +++ b/libavformat/rtpproto.h @@ -26,6 +26,5 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri); int ff_rtp_get_local_rtp_port(URLContext *h); -int ff_rtp_get_local_rtcp_port(URLContext *h); #endif /* AVFORMAT_RTPPROTO_H */ diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index b6da61b95..cf7cdb2f2 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -2009,7 +2009,9 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, } #if CONFIG_RTSP_DEMUXER if (rt->rtsp_hd && p[0].revents & POLLIN) { - return parse_rtsp_message(s); + if ((ret = parse_rtsp_message(s)) < 0) { + return ret; + } } #endif } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) { diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 0242ca379..e7149167a 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -584,6 +584,12 @@ static char *sdp_write_media_attributes(char *buff, int size, AVStream *st, int payload_type, p->sample_rate, p->channels); break; + case AV_CODEC_ID_PCM_S24BE: + if (payload_type >= RTP_PT_PRIVATE) + av_strlcatf(buff, size, "a=rtpmap:%d L24/%d/%d\r\n", + payload_type, + p->sample_rate, p->channels); + break; case AV_CODEC_ID_PCM_MULAW: if (payload_type >= RTP_PT_PRIVATE) av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n", diff --git a/libavformat/spdifdec.c b/libavformat/spdifdec.c index f7288376f..21bfce422 100644 --- a/libavformat/spdifdec.c +++ b/libavformat/spdifdec.c @@ -25,18 +25,22 @@ * @author Anssi Hannula */ +#include "libavutil/bswap.h" + +#include "libavcodec/ac3.h" +#include "libavcodec/adts_parser.h" + #include "avformat.h" #include "spdif.h" -#include "libavcodec/ac3.h" -#include "libavcodec/aacadtsdec.h" static int spdif_get_offset_and_codec(AVFormatContext *s, enum IEC61937DataType data_type, const char *buf, int *offset, enum AVCodecID *codec) { - AACADTSHeaderInfo aac_hdr; - GetBitContext gbc; + uint32_t samples; + uint8_t frames; + int ret; switch (data_type & 0xff) { case IEC61937_AC3: @@ -56,13 +60,13 @@ static int spdif_get_offset_and_codec(AVFormatContext *s, *codec = AV_CODEC_ID_MP3; break; case IEC61937_MPEG2_AAC: - init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8); - if (avpriv_aac_parse_header(&gbc, &aac_hdr) < 0) { + ret = av_adts_header_parse(buf, &samples, &frames); + if (ret < 0) { if (s) /* be silent during a probe */ av_log(s, AV_LOG_ERROR, "Invalid AAC packet in IEC 61937\n"); - return AVERROR_INVALIDDATA; + return ret; } - *offset = aac_hdr.samples << 2; + *offset = samples << 2; *codec = AV_CODEC_ID_AAC; break; case IEC61937_MPEG2_LAYER1_LSF: @@ -100,7 +104,7 @@ static int spdif_get_offset_and_codec(AVFormatContext *s, } /* Largest offset between bursts we currently handle, i.e. AAC with - aac_hdr.samples = 4096 */ + samples = 4096 */ #define SPDIF_MAX_OFFSET 16384 static int spdif_probe(AVProbeData *p) @@ -132,7 +136,7 @@ int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec) } else consecutive_codes = 0; - if (buf + 4 + AAC_ADTS_HEADER_SIZE > p_buf + buf_size) + if (buf + 4 + AV_AAC_ADTS_HEADER_SIZE > p_buf + buf_size) break; /* continue probing to find more sync codes */ diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index b47ec123e..3a50aebbe 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -50,9 +50,9 @@ #include "avio_internal.h" #include "spdif.h" #include "libavcodec/ac3.h" +#include "libavcodec/adts_parser.h" #include "libavcodec/dca.h" #include "libavcodec/dca_syncwords.h" -#include "libavcodec/aacadtsdec.h" #include "libavutil/opt.h" typedef struct IEC61937Context { @@ -349,19 +349,18 @@ static int spdif_header_mpeg(AVFormatContext *s, AVPacket *pkt) static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt) { IEC61937Context *ctx = s->priv_data; - AACADTSHeaderInfo hdr; - GetBitContext gbc; + uint32_t samples; + uint8_t frames; int ret; - init_get_bits(&gbc, pkt->data, AAC_ADTS_HEADER_SIZE * 8); - ret = avpriv_aac_parse_header(&gbc, &hdr); + ret = av_adts_header_parse(pkt->data, &samples, &frames); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Wrong AAC file format\n"); - return AVERROR_INVALIDDATA; + return ret; } - ctx->pkt_offset = hdr.samples << 2; - switch (hdr.num_aac_frames) { + ctx->pkt_offset = samples << 2; + switch (frames) { case 1: ctx->data_type = IEC61937_MPEG2_AAC; break; @@ -373,7 +372,7 @@ static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt) break; default: av_log(s, AV_LOG_ERROR, - "%"PRIu32" samples in AAC frame not supported\n", hdr.samples); + "%"PRIu32" samples in AAC frame not supported\n", samples); return AVERROR(EINVAL); } //TODO Data type dependent info (LC profile/SBR) diff --git a/libavformat/subfile.c b/libavformat/subfile.c index 497cf8521..b527f2bee 100644 --- a/libavformat/subfile.c +++ b/libavformat/subfile.c @@ -72,6 +72,9 @@ static int subfile_open(URLContext *h, const char *filename, int flags, SubfileContext *c = h->priv_data; int ret; + if (!c->end) + c->end = INT64_MAX; + if (c->end <= c->start) { av_log(h, AV_LOG_ERROR, "end before start\n"); return AVERROR(EINVAL); diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c index cada45ef9..f53db0fb2 100644 --- a/libavformat/swfenc.c +++ b/libavformat/swfenc.c @@ -69,7 +69,7 @@ static inline void max_nbits(int *nbits_ptr, int val) if (val == 0) return; - val = abs(val); + val = FFABS(val); n = 1; while (val != 0) { n++; diff --git a/libavformat/takdec.c b/libavformat/takdec.c index 1535bec64..6fda35c1b 100644 --- a/libavformat/takdec.c +++ b/libavformat/takdec.c @@ -103,7 +103,6 @@ static int tak_read_header(AVFormatContext *s) } } - init_get_bits8(&gb, buffer, size - 3); break; case TAK_METADATA_MD5: { uint8_t md5[16]; @@ -145,7 +144,9 @@ static int tak_read_header(AVFormatContext *s) if (type == TAK_METADATA_STREAMINFO) { TAKStreamInfo ti; - avpriv_tak_parse_streaminfo(&gb, &ti); + ret = avpriv_tak_parse_streaminfo(&ti, buffer, size -3); + if (ret < 0) + return AVERROR_INVALIDDATA; if (ti.samples > 0) st->duration = ti.samples; st->codecpar->bits_per_coded_sample = ti.bps; @@ -161,11 +162,13 @@ static int tak_read_header(AVFormatContext *s) } else if (type == TAK_METADATA_LAST_FRAME) { if (size != 11) return AVERROR_INVALIDDATA; + init_get_bits8(&gb, buffer, size - 3); tc->mlast_frame = 1; tc->data_end = get_bits64(&gb, TAK_LAST_FRAME_POS_BITS) + get_bits(&gb, TAK_LAST_FRAME_SIZE_BITS); av_freep(&buffer); } else if (type == TAK_METADATA_ENCODER) { + init_get_bits8(&gb, buffer, size - 3); av_log(s, AV_LOG_VERBOSE, "encoder version: %0X\n", get_bits_long(&gb, TAK_ENCODER_VERSION_BITS)); av_freep(&buffer); diff --git a/libavformat/tcp.c b/libavformat/tcp.c index 07b4ed9fa..8773493df 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -41,6 +41,7 @@ typedef struct TCPContext { int listen_timeout; int recv_buffer_size; int send_buffer_size; + int tcp_nodelay; } TCPContext; #define OFFSET(x) offsetof(TCPContext, x) @@ -52,6 +53,7 @@ static const AVOption options[] = { { "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "tcp_nodelay", "Use TCP_NODELAY to disable nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E }, { NULL } }; @@ -148,6 +150,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (s->send_buffer_size > 0) { setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size)); } + if (s->tcp_nodelay > 0) { + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &s->tcp_nodelay, sizeof (s->tcp_nodelay)); + } if (s->listen == 2) { // multi-client @@ -220,6 +225,8 @@ static int tcp_read(URLContext *h, uint8_t *buf, int size) return ret; } ret = recv(s->fd, buf, size, 0); + if (ret == 0) + return AVERROR_EOF; return ret < 0 ? ff_neterrno() : ret; } @@ -270,7 +277,7 @@ static int tcp_get_window_size(URLContext *h) { TCPContext *s = h->priv_data; int avail; - int avail_len = sizeof(avail); + socklen_t avail_len = sizeof(avail); #if HAVE_WINSOCK2_H /* SO_RCVBUF with winsock only reports the actual TCP window size when diff --git a/libavformat/tests/.gitignore b/libavformat/tests/.gitignore new file mode 100644 index 000000000..7ceb7a356 --- /dev/null +++ b/libavformat/tests/.gitignore @@ -0,0 +1,7 @@ +/fifo_muxer +/movenc +/noproxy +/rtmpdh +/seek +/srtp +/url diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c index e20bd6e7b..4b63df085 100644 --- a/libavformat/tests/fifo_muxer.c +++ b/libavformat/tests/fifo_muxer.c @@ -238,54 +238,6 @@ fail: return ret; } -static int fifo_write_header_err_tst(AVFormatContext *oc, AVDictionary **opts, - const FailingMuxerPacketData *pkt_data) -{ - int ret = 0, i; - AVPacket pkt; - - av_init_packet(&pkt); - - ret = avformat_write_header(oc, opts); - if (ret) { - fprintf(stderr, "Unexpected write_header failure: %s\n", - av_err2str(ret)); - goto fail; - } - - for (i = 0; i < MAX_TST_PACKETS; i++ ) { - ret = prepare_packet(&pkt, pkt_data, i); - if (ret < 0) { - fprintf(stderr, "Failed to prepare test packet: %s\n", - av_err2str(ret)); - goto write_trailer_and_fail; - } - ret = av_write_frame(oc, &pkt); - av_packet_unref(&pkt); - if (ret < 0) { - break; - } - } - - if (!ret) { - fprintf(stderr, "write_packet not failed when supposed to.\n"); - goto fail; - } else if (ret != -1) { - fprintf(stderr, "Unexpected write_packet error: %s\n", av_err2str(ret)); - goto fail; - } - - ret = av_write_trailer(oc); - if (ret < 0) - fprintf(stderr, "Unexpected write_trailer error: %s\n", av_err2str(ret)); - - return ret; -write_trailer_and_fail: - av_write_trailer(oc); -fail: - return ret; -} - static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, const FailingMuxerPacketData *data) { @@ -403,10 +355,6 @@ const TestCase tests[] = { * exactly what was on input */ {fifo_basic_test, "nonfail test", NULL,1, 0, 0, {0, 0, 0}}, - /* Test that we receive delayed write_header error from one of the write_packet - * calls. */ - {fifo_write_header_err_tst, "write header error test", NULL, 0, -1, 0, {0, 0, 0}}, - /* Each write_packet will fail 3 times before operation is successful. If recovery * Since recovery is on, fifo muxer should not return any errors. */ {fifo_basic_test, "recovery test", "attempt_recovery=1:recovery_wait_time=0", diff --git a/libavformat/tests/movenc.c b/libavformat/tests/movenc.c index 8e59b7425..ad6c92a94 100644 --- a/libavformat/tests/movenc.c +++ b/libavformat/tests/movenc.c @@ -115,6 +115,7 @@ static int io_write_data_type(void *opaque, uint8_t *buf, int size, case AVIO_DATA_MARKER_BOUNDARY_POINT: str = "boundary"; break; case AVIO_DATA_MARKER_UNKNOWN: str = "unknown"; break; case AVIO_DATA_MARKER_TRAILER: str = "trailer"; break; + default: str = "unknown"; break; } if (time == AV_NOPTS_VALUE) snprintf(timebuf, sizeof(timebuf), "nopts"); diff --git a/libavformat/tests/seek.c b/libavformat/tests/seek.c index 5cf3a123e..7ed56ba4e 100644 --- a/libavformat/tests/seek.c +++ b/libavformat/tests/seek.c @@ -67,8 +67,6 @@ int main(int argc, char **argv) int frame_count = 1; int duration = 4; - ic->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - for(i=2; ipriv_data; - int ret = gnutls_record_recv(c->session, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = gnutls_record_recv(c->session, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -234,7 +245,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int size) static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; - int ret = gnutls_record_send(c->session, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = gnutls_record_send(c->session, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -260,7 +275,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_gnutls_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/tls_libtls.c b/libavformat/tls_libtls.c new file mode 100644 index 000000000..1321f7922 --- /dev/null +++ b/libavformat/tls_libtls.c @@ -0,0 +1,207 @@ +/* + * TLS/SSL Protocol + * Copyright (c) 2011 Martin Storsjo + * Copyright (c) 2017 sfan5 + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" +#include "network.h" +#include "url.h" +#include "tls.h" +#include "libavcodec/internal.h" +#include "libavutil/avutil.h" +#include "libavutil/opt.h" + +#include + +typedef struct TLSContext { + const AVClass *class; + TLSShared tls_shared; + struct tls *ctx; +} TLSContext; + +static int ff_tls_close(URLContext *h) +{ + TLSContext *p = h->priv_data; + if (p->ctx) { + tls_close(p->ctx); + tls_free(p->ctx); + } + if (p->tls_shared.tcp) + ffurl_close(p->tls_shared.tcp); + return 0; +} + +static ssize_t tls_read_callback(struct tls *ctx, void *buf, size_t buflen, void *cb_arg) +{ + URLContext *h = (URLContext*) cb_arg; + int ret = ffurl_read(h, buf, buflen); + if (ret == AVERROR(EAGAIN)) + return TLS_WANT_POLLIN; + else if (ret == AVERROR_EXIT) + return 0; + return ret >= 0 ? ret : -1; +} + +static ssize_t tls_write_callback(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg) +{ + URLContext *h = (URLContext*) cb_arg; + int ret = ffurl_write(h, buf, buflen); + if (ret == AVERROR(EAGAIN)) + return TLS_WANT_POLLOUT; + else if (ret == AVERROR_EXIT) + return 0; + return ret >= 0 ? ret : -1; +} + +static int ff_tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) +{ + TLSContext *p = h->priv_data; + TLSShared *c = &p->tls_shared; + struct tls_config *cfg = NULL; + int ret; + + if (tls_init() == -1) { + ret = AVERROR(EIO); + goto fail; + } + + if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) + goto fail; + + p->ctx = !c->listen ? tls_client() : tls_server(); + if (!p->ctx) { + ret = AVERROR(EIO); + goto fail; + } + + cfg = tls_config_new(); + if (!p->ctx) { + ret = AVERROR(EIO); + goto fail; + } + if (tls_config_set_protocols(cfg, TLS_PROTOCOLS_ALL) == -1) + goto err_config; + // While TLSv1.0 and TLSv1.1 are already enabled by the above, + // we need to be less strict with ciphers so it works in practice. + if (tls_config_set_ciphers(cfg, "compat") == -1) + goto err_config; + if (c->ca_file && tls_config_set_ca_file(cfg, c->ca_file) == -1) + goto err_config; + if (c->cert_file && tls_config_set_cert_file(cfg, c->cert_file) == -1) + goto err_config; + if (c->key_file && tls_config_set_key_file(cfg, c->key_file) == -1) + goto err_config; + if (!c->verify) { + tls_config_insecure_noverifycert(cfg); + tls_config_insecure_noverifyname(cfg); + tls_config_insecure_noverifytime(cfg); + } + if (tls_configure(p->ctx, cfg) == -1) + goto err_ctx; + + if (!c->listen) { + ret = tls_connect_cbs(p->ctx, tls_read_callback, tls_write_callback, + c->tcp, !c->numerichost ? c->host : NULL); + } else { + struct tls *ctx_new; + ret = tls_accept_cbs(p->ctx, &ctx_new, tls_read_callback, + tls_write_callback, c->tcp); + if (ret == 0) { + // free "server" context and replace by "connection" context + tls_free(p->ctx); + p->ctx = ctx_new; + } + } + if (ret == -1) + goto err_ctx; + + tls_config_free(cfg); + return 0; +err_config: + av_log(h, AV_LOG_ERROR, "%s\n", tls_config_error(cfg)); + ret = AVERROR(EIO); + goto fail; +err_ctx: + av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); + ret = AVERROR(EIO); + /* fallthrough */ +fail: + if (cfg) + tls_config_free(cfg); + ff_tls_close(h); + return ret; +} + +static int ff_tls_read(URLContext *h, uint8_t *buf, int size) +{ + TLSContext *p = h->priv_data; + ssize_t ret; + ret = tls_read(p->ctx, buf, size); + if (ret > 0) + return ret; + else if (ret == 0) + return AVERROR_EOF; + av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); + return AVERROR(EIO); +} + +static int ff_tls_write(URLContext *h, const uint8_t *buf, int size) +{ + TLSContext *p = h->priv_data; + ssize_t ret; + ret = tls_write(p->ctx, buf, size); + if (ret > 0) + return ret; + else if (ret == 0) + return AVERROR_EOF; + av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); + return AVERROR(EIO); +} + +static int tls_get_file_handle(URLContext *h) +{ + TLSContext *c = h->priv_data; + return ffurl_get_file_handle(c->tls_shared.tcp); +} + +static const AVOption options[] = { + TLS_COMMON_OPTIONS(TLSContext, tls_shared), + { NULL } +}; + +static const AVClass tls_class = { + .class_name = "tls", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const URLProtocol ff_tls_protocol = { + .name = "tls", + .url_open2 = ff_tls_open, + .url_read = ff_tls_read, + .url_write = ff_tls_write, + .url_close = ff_tls_close, + .url_get_file_handle = tls_get_file_handle, + .priv_data_size = sizeof(TLSContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &tls_class, +}; diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 38af8a21c..59a86150a 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -66,6 +66,85 @@ static unsigned long openssl_thread_id(void) #endif #endif +int ff_openssl_init(void) +{ + ff_lock_avformat(); + if (!openssl_init) { + SSL_library_init(); + SSL_load_error_strings(); +#if HAVE_THREADS + if (!CRYPTO_get_locking_callback()) { + int i; + openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); + if (!openssl_mutexes) { + ff_unlock_avformat(); + return AVERROR(ENOMEM); + } + + for (i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_init(&openssl_mutexes[i], NULL); + CRYPTO_set_locking_callback(openssl_lock); +#if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 + CRYPTO_set_id_callback(openssl_thread_id); +#endif + } +#endif + } + openssl_init++; + ff_unlock_avformat(); + + return 0; +} + +void ff_openssl_deinit(void) +{ + ff_lock_avformat(); + openssl_init--; + if (!openssl_init) { +#if HAVE_THREADS + if (CRYPTO_get_locking_callback() == openssl_lock) { + int i; + CRYPTO_set_locking_callback(NULL); + for (i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_destroy(&openssl_mutexes[i]); + av_free(openssl_mutexes); + } +#endif + } + ff_unlock_avformat(); +} + +static int print_tls_error(URLContext *h, int ret) +{ + TLSContext *c = h->priv_data; + if (h->flags & AVIO_FLAG_NONBLOCK) { + int err = SSL_get_error(c->ssl, ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_READ) + return AVERROR(EAGAIN); + } + av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); + return AVERROR(EIO); +} + +static int tls_close(URLContext *h) +{ + TLSContext *c = h->priv_data; + if (c->ssl) { + SSL_shutdown(c->ssl); + SSL_free(c->ssl); + } + if (c->ctx) + SSL_CTX_free(c->ctx); + if (c->tls_shared.tcp) + ffurl_close(c->tls_shared.tcp); +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL + if (c->url_bio_method) + BIO_meth_free(c->url_bio_method); +#endif + ff_openssl_deinit(); + return 0; +} + static int url_bio_create(BIO *b) { #if OPENSSL_VERSION_NUMBER >= 0x1010000fL @@ -98,6 +177,8 @@ static int url_bio_bread(BIO *b, char *buf, int len) if (ret >= 0) return ret; BIO_clear_retry_flags(b); + if (ret == AVERROR(EAGAIN)) + BIO_set_retry_read(b); if (ret == AVERROR_EXIT) return 0; return -1; @@ -110,6 +191,8 @@ static int url_bio_bwrite(BIO *b, const char *buf, int len) if (ret >= 0) return ret; BIO_clear_retry_flags(b); + if (ret == AVERROR(EAGAIN)) + BIO_set_retry_write(b); if (ret == AVERROR_EXIT) return 0; return -1; @@ -143,79 +226,6 @@ static BIO_METHOD url_bio_method = { }; #endif -int ff_openssl_init(void) -{ - avpriv_lock_avformat(); - if (!openssl_init) { - SSL_library_init(); - SSL_load_error_strings(); -#if HAVE_THREADS - if (!CRYPTO_get_locking_callback()) { - int i; - openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); - if (!openssl_mutexes) { - avpriv_unlock_avformat(); - return AVERROR(ENOMEM); - } - - for (i = 0; i < CRYPTO_num_locks(); i++) - pthread_mutex_init(&openssl_mutexes[i], NULL); - CRYPTO_set_locking_callback(openssl_lock); -#if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 - CRYPTO_set_id_callback(openssl_thread_id); -#endif - } -#endif - } - openssl_init++; - avpriv_unlock_avformat(); - - return 0; -} - -void ff_openssl_deinit(void) -{ - avpriv_lock_avformat(); - openssl_init--; - if (!openssl_init) { -#if HAVE_THREADS - if (CRYPTO_get_locking_callback() == openssl_lock) { - int i; - CRYPTO_set_locking_callback(NULL); - for (i = 0; i < CRYPTO_num_locks(); i++) - pthread_mutex_destroy(&openssl_mutexes[i]); - av_free(openssl_mutexes); - } -#endif - } - avpriv_unlock_avformat(); -} - -static int print_tls_error(URLContext *h, int ret) -{ - av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); - return AVERROR(EIO); -} - -static int tls_close(URLContext *h) -{ - TLSContext *c = h->priv_data; - if (c->ssl) { - SSL_shutdown(c->ssl); - SSL_free(c->ssl); - } - if (c->ctx) - SSL_CTX_free(c->ctx); - if (c->tls_shared.tcp) - ffurl_close(c->tls_shared.tcp); -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL - if (c->url_bio_method) - BIO_meth_free(c->url_bio_method); -#endif - ff_openssl_deinit(); - return 0; -} - static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { TLSContext *p = h->priv_data; @@ -302,7 +312,11 @@ fail: static int tls_read(URLContext *h, uint8_t *buf, int size) { TLSContext *c = h->priv_data; - int ret = SSL_read(c->ssl, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = SSL_read(c->ssl, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -313,7 +327,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int size) static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; - int ret = SSL_write(c->ssl, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = SSL_write(c->ssl, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -339,7 +357,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_openssl_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/tls_schannel.c b/libavformat/tls_schannel.c index 9f1c08806..9a6e0c92e 100644 --- a/libavformat/tls_schannel.c +++ b/libavformat/tls_schannel.c @@ -595,7 +595,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_schannel_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/tls_securetransport.c b/libavformat/tls_securetransport.c index bc8a32069..37380541b 100644 --- a/libavformat/tls_securetransport.c +++ b/libavformat/tls_securetransport.c @@ -54,7 +54,7 @@ static int print_tls_error(URLContext *h, int ret) TLSContext *c = h->priv_data; switch (ret) { case errSSLWouldBlock: - break; + return AVERROR(EAGAIN); case errSSLXCertChainInvalid: av_log(h, AV_LOG_ERROR, "Invalid certificate chain\n"); return AVERROR(EIO); @@ -69,6 +69,9 @@ static int print_tls_error(URLContext *h, int ret) static int import_pem(URLContext *h, char *path, CFArrayRef *array) { +#if !HAVE_SECITEMIMPORT + return AVERROR_PATCHWELCOME; +#else AVIOContext *s = NULL; CFDataRef data = NULL; int64_t ret = 0; @@ -124,6 +127,7 @@ end: if (s) avio_close(s); return ret; +#endif } static int load_ca(URLContext *h) @@ -193,7 +197,8 @@ static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dat { URLContext *h = (URLContext*)connection; TLSContext *c = h->priv_data; - int read = ffurl_read_complete(c->tls_shared.tcp, data, *dataLength); + size_t requested = *dataLength; + int read = ffurl_read(c->tls_shared.tcp, data, requested); if (read <= 0) { *dataLength = 0; switch(AVUNERROR(read)) { @@ -210,7 +215,10 @@ static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dat } } else { *dataLength = read; - return noErr; + if (read < requested) + return errSSLWouldBlock; + else + return noErr; } } @@ -322,12 +330,13 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op if (peerTrust) CFRelease(peerTrust); } - if (status == noErr) + if (status == noErr) { break; - - av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status); - ret = AVERROR(EIO); - goto fail; + } else if (status != errSSLWouldBlock) { + av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status); + ret = AVERROR(EIO); + goto fail; + } } return 0; @@ -344,6 +353,9 @@ static int map_ssl_error(OSStatus status, size_t processed) case errSSLClosedGraceful: case errSSLClosedNoNotify: return 0; + case errSSLWouldBlock: + if (processed > 0) + return processed; default: return (int)status; } @@ -352,8 +364,12 @@ static int map_ssl_error(OSStatus status, size_t processed) static int tls_read(URLContext *h, uint8_t *buf, int size) { TLSContext *c = h->priv_data; - size_t processed = 0; - int ret = SSLRead(c->ssl_context, buf, size, &processed); + size_t available = 0, processed = 0; + int ret; + SSLGetBufferedReadSize(c->ssl_context, &available); + if (available) + size = FFMIN(available, size); + ret = SSLRead(c->ssl_context, buf, size, &processed); ret = map_ssl_error(ret, processed); if (ret > 0) return ret; @@ -393,7 +409,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_securetransport_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/ttaenc.c b/libavformat/ttaenc.c index fdce1e3dc..add15873d 100644 --- a/libavformat/ttaenc.c +++ b/libavformat/ttaenc.c @@ -29,22 +29,23 @@ typedef struct TTAMuxContext { AVIOContext *seek_table; - AVIOContext *data; + AVPacketList *queue, *queue_end; uint32_t nb_samples; int frame_size; int last_frame; } TTAMuxContext; -static int tta_write_header(AVFormatContext *s) +static int tta_init(AVFormatContext *s) { TTAMuxContext *tta = s->priv_data; - AVCodecParameters *par = s->streams[0]->codecpar; - int ret; + AVCodecParameters *par; if (s->nb_streams != 1) { av_log(s, AV_LOG_ERROR, "Only one stream is supported\n"); return AVERROR(EINVAL); } + par = s->streams[0]->codecpar; + if (par->codec_id != AV_CODEC_ID_TTA) { av_log(s, AV_LOG_ERROR, "Unsupported codec\n"); return AVERROR(EINVAL); @@ -54,22 +55,6 @@ static int tta_write_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } - if ((ret = avio_open_dyn_buf(&tta->seek_table)) < 0) - return ret; - if ((ret = avio_open_dyn_buf(&tta->data)) < 0) { - ffio_free_dyn_buf(&tta->seek_table); - return ret; - } - - /* Ignore most extradata information if present. It can be innacurate - if for example remuxing from Matroska */ - ffio_init_checksum(s->pb, ff_crcEDB88320_update, UINT32_MAX); - ffio_init_checksum(tta->seek_table, ff_crcEDB88320_update, UINT32_MAX); - avio_write(s->pb, "TTA1", 4); - avio_wl16(s->pb, par->extradata ? AV_RL16(par->extradata + 4) : 1); - avio_wl16(s->pb, par->channels); - avio_wl16(s->pb, par->bits_per_raw_sample); - avio_wl32(s->pb, par->sample_rate); /* Prevent overflow */ if (par->sample_rate > 0x7FFFFFu) { av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); @@ -81,11 +66,48 @@ static int tta_write_header(AVFormatContext *s) return 0; } +static int tta_write_header(AVFormatContext *s) +{ + TTAMuxContext *tta = s->priv_data; + AVCodecParameters *par = s->streams[0]->codecpar; + int ret; + + if ((ret = avio_open_dyn_buf(&tta->seek_table)) < 0) + return ret; + + /* Ignore most extradata information if present. It can be innacurate + if for example remuxing from Matroska */ + ffio_init_checksum(s->pb, ff_crcEDB88320_update, UINT32_MAX); + ffio_init_checksum(tta->seek_table, ff_crcEDB88320_update, UINT32_MAX); + avio_write(s->pb, "TTA1", 4); + avio_wl16(s->pb, par->extradata ? AV_RL16(par->extradata + 4) : 1); + avio_wl16(s->pb, par->channels); + avio_wl16(s->pb, par->bits_per_raw_sample); + avio_wl32(s->pb, par->sample_rate); + + return 0; +} + static int tta_write_packet(AVFormatContext *s, AVPacket *pkt) { TTAMuxContext *tta = s->priv_data; + AVPacketList *pktl = av_mallocz(sizeof(*pktl)); + int ret; + + if (!pktl) + return AVERROR(ENOMEM); + + ret = av_packet_ref(&pktl->pkt, pkt); + if (ret < 0) { + av_free(pktl); + return ret; + } + if (tta->queue_end) + tta->queue_end->next = pktl; + else + tta->queue = pktl; + tta->queue_end = pktl; - avio_write(tta->data, pkt->data, pkt->size); avio_wl32(tta->seek_table, pkt->size); tta->nb_samples += pkt->duration; @@ -106,6 +128,21 @@ static int tta_write_packet(AVFormatContext *s, AVPacket *pkt) return 0; } +static void tta_queue_flush(AVFormatContext *s) +{ + TTAMuxContext *tta = s->priv_data; + AVPacketList *pktl; + + while (pktl = tta->queue) { + AVPacket *pkt = &pktl->pkt; + avio_write(s->pb, pkt->data, pkt->size); + av_packet_unref(pkt); + tta->queue = pktl->next; + av_free(pktl); + } + tta->queue_end = NULL; +} + static int tta_write_trailer(AVFormatContext *s) { TTAMuxContext *tta = s->priv_data; @@ -125,9 +162,7 @@ static int tta_write_trailer(AVFormatContext *s) av_free(ptr); /* Write audio data */ - size = avio_close_dyn_buf(tta->data, &ptr); - avio_write(s->pb, ptr, size); - av_free(ptr); + tta_queue_flush(s); ff_ape_write_tag(s); avio_flush(s->pb); @@ -143,6 +178,7 @@ AVOutputFormat ff_tta_muxer = { .priv_data_size = sizeof(TTAMuxContext), .audio_codec = AV_CODEC_ID_TTA, .video_codec = AV_CODEC_ID_NONE, + .init = tta_init, .write_header = tta_write_header, .write_packet = tta_write_packet, .write_trailer = tta_write_trailer, diff --git a/libavformat/ty.c b/libavformat/ty.c new file mode 100644 index 000000000..d348643f4 --- /dev/null +++ b/libavformat/ty.c @@ -0,0 +1,789 @@ +/* + * TiVo ty stream demuxer + * Copyright (c) 2005 VLC authors and VideoLAN + * Copyright (c) 2005 by Neal Symms (tivo@freakinzoo.com) - February 2005 + * based on code by Christopher Wingert for tivo-mplayer + * tivo(at)wingert.org, February 2003 + * 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 "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "mpeg.h" + +#define SERIES1_PES_LENGTH 11 /* length of audio PES hdr on S1 */ +#define SERIES2_PES_LENGTH 16 /* length of audio PES hdr on S2 */ +#define AC3_PES_LENGTH 14 /* length of audio PES hdr for AC3 */ +#define VIDEO_PES_LENGTH 16 /* length of video PES header */ +#define DTIVO_PTS_OFFSET 6 /* offs into PES for MPEG PTS on DTivo */ +#define SA_PTS_OFFSET 9 /* offset into PES for MPEG PTS on SA */ +#define AC3_PTS_OFFSET 9 /* offset into PES for AC3 PTS on DTivo */ +#define VIDEO_PTS_OFFSET 9 /* offset into PES for video PTS on all */ +#define AC3_PKT_LENGTH 1536 /* size of TiVo AC3 pkts (w/o PES hdr) */ + +static const uint8_t ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 }; +static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 }; +static const uint8_t ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd }; + +#define TIVO_PES_FILEID 0xf5467abd +#define CHUNK_SIZE (128 * 1024) +#define CHUNK_PEEK_COUNT 3 /* number of chunks to probe */ + +typedef struct TyRecHdr { + int64_t rec_size; + uint8_t ex[2]; + uint8_t rec_type; + uint8_t subrec_type; + uint64_t ty_pts; /* TY PTS in the record header */ +} TyRecHdr; + +typedef enum { + TIVO_TYPE_UNKNOWN, + TIVO_TYPE_SA, + TIVO_TYPE_DTIVO +} TiVo_type; + +typedef enum { + TIVO_SERIES_UNKNOWN, + TIVO_SERIES1, + TIVO_SERIES2 +} TiVo_series; + +typedef enum { + TIVO_AUDIO_UNKNOWN, + TIVO_AUDIO_AC3, + TIVO_AUDIO_MPEG +} TiVo_audio; + +typedef struct TySeqTable { + uint64_t timestamp; + uint8_t chunk_bitmask[8]; +} TySeqTable; + +typedef struct TYDemuxContext { + unsigned cur_chunk; + unsigned cur_chunk_pos; + int64_t cur_pos; + TiVo_type tivo_type; /* TiVo type (SA / DTiVo) */ + TiVo_series tivo_series; /* Series1 or Series2 */ + TiVo_audio audio_type; /* AC3 or MPEG */ + int pes_length; /* Length of Audio PES header */ + int pts_offset; /* offset into audio PES of PTS */ + uint8_t pes_buffer[20]; /* holds incomplete pes headers */ + int pes_buf_cnt; /* how many bytes in our buffer */ + size_t ac3_pkt_size; /* length of ac3 pkt we've seen so far */ + uint64_t last_ty_pts; /* last TY timestamp we've seen */ + unsigned seq_table_size; /* number of entries in SEQ table */ + + int64_t first_audio_pts; + int64_t last_audio_pts; + int64_t last_video_pts; + + TyRecHdr *rec_hdrs; /* record headers array */ + int cur_rec; /* current record in this chunk */ + int num_recs; /* number of recs in this chunk */ + int seq_rec; /* record number where seq start is */ + TySeqTable *seq_table; /* table of SEQ entries from mstr chk */ + int first_chunk; + + uint8_t chunk[CHUNK_SIZE]; +} TYDemuxContext; + +static int ty_probe(AVProbeData *p) +{ + int i; + + for (i = 0; i + 12 < p->buf_size; i += CHUNK_SIZE) { + if (AV_RB32(p->buf + i) == TIVO_PES_FILEID && + AV_RB32(p->buf + i + 4) == 0x02 && + AV_RB32(p->buf + i + 8) == CHUNK_SIZE) { + return AVPROBE_SCORE_MAX; + } + } + + return 0; +} + +static TyRecHdr *parse_chunk_headers(const uint8_t *buf, + int num_recs) +{ + TyRecHdr *hdrs, *rec_hdr; + int i; + + hdrs = av_calloc(num_recs, sizeof(TyRecHdr)); + if (!hdrs) + return NULL; + + for (i = 0; i < num_recs; i++) { + const uint8_t *record_header = buf + (i * 16); + + rec_hdr = &hdrs[i]; /* for brevity */ + rec_hdr->rec_type = record_header[3]; + rec_hdr->subrec_type = record_header[2] & 0x0f; + if ((record_header[0] & 0x80) == 0x80) { + uint8_t b1, b2; + + /* marker bit 2 set, so read extended data */ + b1 = (((record_header[0] & 0x0f) << 4) | + ((record_header[1] & 0xf0) >> 4)); + b2 = (((record_header[1] & 0x0f) << 4) | + ((record_header[2] & 0xf0) >> 4)); + + rec_hdr->ex[0] = b1; + rec_hdr->ex[1] = b2; + rec_hdr->rec_size = 0; + rec_hdr->ty_pts = 0; + } else { + rec_hdr->rec_size = (record_header[0] << 8 | + record_header[1]) << 4 | + (record_header[2] >> 4); + rec_hdr->ty_pts = AV_RB64(&record_header[8]); + } + } + return hdrs; +} + +static int find_es_header(const uint8_t *header, + const uint8_t *buffer, int search_len) +{ + int count; + + for (count = 0; count < search_len; count++) { + if (!memcmp(&buffer[count], header, 4)) + return count; + } + return -1; +} + +static int analyze_chunk(AVFormatContext *s, const uint8_t *chunk) +{ + TYDemuxContext *ty = s->priv_data; + int num_recs, i; + TyRecHdr *hdrs; + int num_6e0, num_be0, num_9c0, num_3c0; + + /* skip if it's a Part header */ + if (AV_RB32(&chunk[0]) == TIVO_PES_FILEID) + return 0; + + /* number of records in chunk (we ignore high order byte; + * rarely are there > 256 chunks & we don't need that many anyway) */ + num_recs = chunk[0]; + if (num_recs < 5) { + /* try again with the next chunk. Sometimes there are dead ones */ + return 0; + } + + chunk += 4; /* skip past rec count & SEQ bytes */ + ff_dlog(s, "probe: chunk has %d recs\n", num_recs); + hdrs = parse_chunk_headers(chunk, num_recs); + if (!hdrs) + return AVERROR(ENOMEM); + + /* scan headers. + * 1. check video packets. Presence of 0x6e0 means S1. + * No 6e0 but have be0 means S2. + * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg) + * If AC-3, then we have DTivo. + * If MPEG, search for PTS offset. This will determine SA vs. DTivo. + */ + num_6e0 = num_be0 = num_9c0 = num_3c0 = 0; + for (i = 0; i < num_recs; i++) { + switch (hdrs[i].subrec_type << 8 | hdrs[i].rec_type) { + case 0x6e0: + num_6e0++; + break; + case 0xbe0: + num_be0++; + break; + case 0x3c0: + num_3c0++; + break; + case 0x9c0: + num_9c0++; + break; + } + } + ff_dlog(s, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.\n", + num_6e0, num_be0); + + /* set up our variables */ + if (num_6e0 > 0) { + ff_dlog(s, "detected Series 1 Tivo\n"); + ty->tivo_series = TIVO_SERIES1; + ty->pes_length = SERIES1_PES_LENGTH; + } else if (num_be0 > 0) { + ff_dlog(s, "detected Series 2 Tivo\n"); + ty->tivo_series = TIVO_SERIES2; + ty->pes_length = SERIES2_PES_LENGTH; + } + if (num_9c0 > 0) { + ff_dlog(s, "detected AC-3 Audio (DTivo)\n"); + ty->audio_type = TIVO_AUDIO_AC3; + ty->tivo_type = TIVO_TYPE_DTIVO; + ty->pts_offset = AC3_PTS_OFFSET; + ty->pes_length = AC3_PES_LENGTH; + } else if (num_3c0 > 0) { + ty->audio_type = TIVO_AUDIO_MPEG; + ff_dlog(s, "detected MPEG Audio\n"); + } + + /* if tivo_type still unknown, we can check PTS location + * in MPEG packets to determine tivo_type */ + if (ty->tivo_type == TIVO_TYPE_UNKNOWN) { + uint32_t data_offset = 16 * num_recs; + + for (i = 0; i < num_recs; i++) { + if (data_offset + hdrs[i].rec_size > CHUNK_SIZE) + break; + + if ((hdrs[i].subrec_type << 0x08 | hdrs[i].rec_type) == 0x3c0 && hdrs[i].rec_size > 15) { + /* first make sure we're aligned */ + int pes_offset = find_es_header(ty_MPEGAudioPacket, + &chunk[data_offset], 5); + if (pes_offset >= 0) { + /* pes found. on SA, PES has hdr data at offset 6, not PTS. */ + if ((chunk[data_offset + 6 + pes_offset] & 0x80) == 0x80) { + /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */ + if (ty->tivo_series == TIVO_SERIES1) + ff_dlog(s, "detected Stand-Alone Tivo\n"); + ty->tivo_type = TIVO_TYPE_SA; + ty->pts_offset = SA_PTS_OFFSET; + } else { + if (ty->tivo_series == TIVO_SERIES1) + ff_dlog(s, "detected DirecTV Tivo\n"); + ty->tivo_type = TIVO_TYPE_DTIVO; + ty->pts_offset = DTIVO_PTS_OFFSET; + } + break; + } + } + data_offset += hdrs[i].rec_size; + } + } + av_free(hdrs); + + return 0; +} + +static int ty_read_header(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st, *ast; + int i, ret = 0; + + ty->first_audio_pts = AV_NOPTS_VALUE; + ty->last_audio_pts = AV_NOPTS_VALUE; + ty->last_video_pts = AV_NOPTS_VALUE; + + for (i = 0; i < CHUNK_PEEK_COUNT; i++) { + avio_read(pb, ty->chunk, CHUNK_SIZE); + + ret = analyze_chunk(s, ty->chunk); + if (ret < 0) + return ret; + if (ty->tivo_series != TIVO_SERIES_UNKNOWN && + ty->audio_type != TIVO_AUDIO_UNKNOWN && + ty->tivo_type != TIVO_TYPE_UNKNOWN) + break; + } + + if (ty->tivo_series == TIVO_SERIES_UNKNOWN || + ty->audio_type == TIVO_AUDIO_UNKNOWN || + ty->tivo_type == TIVO_TYPE_UNKNOWN) + return AVERROR(EIO); + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_MPEG2VIDEO; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + avpriv_set_pts_info(st, 64, 1, 90000); + + ast = avformat_new_stream(s, NULL); + if (!ast) + return AVERROR(ENOMEM); + ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + + if (ty->audio_type == TIVO_AUDIO_MPEG) { + ast->codecpar->codec_id = AV_CODEC_ID_MP2; + ast->need_parsing = AVSTREAM_PARSE_FULL_RAW; + } else { + ast->codecpar->codec_id = AV_CODEC_ID_AC3; + } + avpriv_set_pts_info(ast, 64, 1, 90000); + + ty->first_chunk = 1; + + avio_seek(pb, 0, SEEK_SET); + + return 0; +} + +/* parse a master chunk, filling the SEQ table and other variables. + * We assume the stream is currently pointing to it. + */ +static void parse_master(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + unsigned map_size; /* size of bitmask, in bytes */ + unsigned i, j; + + /* Note that the entries in the SEQ table in the stream may have + different sizes depending on the bits per entry. We store them + all in the same size structure, so we have to parse them out one + by one. If we had a dynamic structure, we could simply read the + entire table directly from the stream into memory in place. */ + + /* clear the SEQ table */ + av_freep(&ty->seq_table); + + /* parse header info */ + + map_size = AV_RB32(ty->chunk + 20); /* size of bitmask, in bytes */ + i = AV_RB32(ty->chunk + 28); /* size of SEQ table, in bytes */ + + ty->seq_table_size = i / (8LL + map_size); + + if (ty->seq_table_size == 0) { + ty->seq_table = NULL; + return; + } + + /* parse all the entries */ + ty->seq_table = av_calloc(ty->seq_table_size, sizeof(TySeqTable)); + if (ty->seq_table == NULL) { + ty->seq_table_size = 0; + return; + } + + ty->cur_chunk_pos = 32; + for (j = 0; j < ty->seq_table_size; j++) { + if (ty->cur_chunk_pos >= CHUNK_SIZE - 8) + return; + ty->seq_table[j].timestamp = AV_RB64(ty->chunk + ty->cur_chunk_pos); + ty->cur_chunk_pos += 8; + if (map_size > 8) { + av_log(s, AV_LOG_ERROR, "Unsupported SEQ bitmap size in master chunk.\n"); + ty->cur_chunk_pos += map_size; + } else { + memcpy(ty->seq_table[j].chunk_bitmask, ty->chunk + ty->cur_chunk_pos, map_size); + } + } +} + +static int get_chunk(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + AVIOContext *pb = s->pb; + int read_size, num_recs; + + ff_dlog(s, "parsing ty chunk #%d\n", ty->cur_chunk); + + /* if we have left-over filler space from the last chunk, get that */ + if (avio_feof(pb)) + return AVERROR_EOF; + + /* read the TY packet header */ + read_size = avio_read(pb, ty->chunk, CHUNK_SIZE); + ty->cur_chunk++; + + if ((read_size < 4) || (AV_RB32(ty->chunk) == 0)) { + return AVERROR_EOF; + } + + /* check if it's a PART Header */ + if (AV_RB32(ty->chunk) == TIVO_PES_FILEID) { + parse_master(s); /* parse master chunk */ + return get_chunk(s); + } + + /* number of records in chunk (8- or 16-bit number) */ + if (ty->chunk[3] & 0x80) { + /* 16 bit rec cnt */ + ty->num_recs = num_recs = (ty->chunk[1] << 8) + ty->chunk[0]; + ty->seq_rec = (ty->chunk[3] << 8) + ty->chunk[2]; + if (ty->seq_rec != 0xffff) { + ty->seq_rec &= ~0x8000; + } + } else { + /* 8 bit reclen - TiVo 1.3 format */ + ty->num_recs = num_recs = ty->chunk[0]; + ty->seq_rec = ty->chunk[1]; + } + ty->cur_rec = 0; + ty->first_chunk = 0; + + ff_dlog(s, "chunk has %d records\n", num_recs); + ty->cur_chunk_pos = 4; + + av_freep(&ty->rec_hdrs); + + if (num_recs * 16 >= CHUNK_SIZE - 4) + return AVERROR_INVALIDDATA; + + ty->rec_hdrs = parse_chunk_headers(ty->chunk + 4, num_recs); + if (!ty->rec_hdrs) + return AVERROR(ENOMEM); + ty->cur_chunk_pos += 16 * num_recs; + + return 0; +} + +static int demux_video(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt) +{ + TYDemuxContext *ty = s->priv_data; + const int subrec_type = rec_hdr->subrec_type; + const int64_t rec_size = rec_hdr->rec_size; + int es_offset1; + int got_packet = 0; + + if (subrec_type != 0x02 && subrec_type != 0x0c && + subrec_type != 0x08 && rec_size > 4) { + /* get the PTS from this packet if it has one. + * on S1, only 0x06 has PES. On S2, however, most all do. + * Do NOT Pass the PES Header to the MPEG2 codec */ + es_offset1 = find_es_header(ty_VideoPacket, ty->chunk + ty->cur_chunk_pos, 5); + if (es_offset1 != -1) { + ty->last_video_pts = ff_parse_pes_pts( + ty->chunk + ty->cur_chunk_pos + es_offset1 + VIDEO_PTS_OFFSET); + if (subrec_type != 0x06) { + /* if we found a PES, and it's not type 6, then we're S2 */ + /* The packet will have video data (& other headers) so we + * chop out the PES header and send the rest */ + if (rec_size >= VIDEO_PES_LENGTH + es_offset1) { + int size = rec_hdr->rec_size - VIDEO_PES_LENGTH - es_offset1; + + ty->cur_chunk_pos += VIDEO_PES_LENGTH + es_offset1; + if (av_new_packet(pkt, size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, size); + ty->cur_chunk_pos += size; + pkt->stream_index = 0; + got_packet = 1; + } else { + ff_dlog(s, "video rec type 0x%02x has short PES" + " (%"PRId64" bytes)\n", subrec_type, rec_size); + /* nuke this block; it's too short, but has PES marker */ + ty->cur_chunk_pos += rec_size; + return 0; + } + } + } + } + + if (subrec_type == 0x06) { + /* type 6 (S1 DTivo) has no data, so we're done */ + ty->cur_chunk_pos += rec_size; + return 0; + } + + if (!got_packet) { + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + pkt->stream_index = 0; + got_packet = 1; + } + + /* if it's not a continue blk, then set PTS */ + if (subrec_type != 0x02) { + if (subrec_type == 0x0c && pkt->size >= 6) + pkt->data[5] |= 0x08; + if (subrec_type == 0x07) { + ty->last_ty_pts = rec_hdr->ty_pts; + } else { + /* yes I know this is a cheap hack. It's the timestamp + used for display and skipping fwd/back, so it + doesn't have to be accurate to the millisecond. + I adjust it here by roughly one 1/30 sec. Yes it + will be slightly off for UK streams, but it's OK. + */ + ty->last_ty_pts += 35000000; + //ty->last_ty_pts += 33366667; + } + /* set PTS for this block before we send */ + if (ty->last_video_pts > AV_NOPTS_VALUE) { + pkt->pts = ty->last_video_pts; + /* PTS gets used ONCE. + * Any subsequent frames we get BEFORE next PES + * header will have their PTS computed in the codec */ + ty->last_video_pts = AV_NOPTS_VALUE; + } + } + + return got_packet; +} + +static int check_sync_pes(AVFormatContext *s, AVPacket *pkt, + int32_t offset, int32_t rec_len) +{ + TYDemuxContext *ty = s->priv_data; + + if (offset < 0 || offset + ty->pes_length > rec_len) { + /* entire PES header not present */ + ff_dlog(s, "PES header at %"PRId32" not complete in record. storing.\n", offset); + /* save the partial pes header */ + if (offset < 0) { + /* no header found, fake some 00's (this works, believe me) */ + memset(ty->pes_buffer, 0, 4); + ty->pes_buf_cnt = 4; + if (rec_len > 4) + ff_dlog(s, "PES header not found in record of %"PRId32" bytes!\n", rec_len); + return -1; + } + /* copy the partial pes header we found */ + memcpy(ty->pes_buffer, pkt->data + offset, rec_len - offset); + ty->pes_buf_cnt = rec_len - offset; + + if (offset > 0) { + /* PES Header was found, but not complete, so trim the end of this record */ + pkt->size -= rec_len - offset; + return 1; + } + return -1; /* partial PES, no audio data */ + } + /* full PES header present, extract PTS */ + ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[ offset + ty->pts_offset]); + if (ty->first_audio_pts == AV_NOPTS_VALUE) + ty->first_audio_pts = ty->last_audio_pts; + pkt->pts = ty->last_audio_pts; + memmove(pkt->data + offset, pkt->data + offset + ty->pes_length, rec_len - ty->pes_length); + pkt->size -= ty->pes_length; + return 0; +} + +static int demux_audio(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt) +{ + TYDemuxContext *ty = s->priv_data; + const int subrec_type = rec_hdr->subrec_type; + const int64_t rec_size = rec_hdr->rec_size; + int es_offset1; + + if (subrec_type == 2) { + int need = 0; + /* SA or DTiVo Audio Data, no PES (continued block) + * ================================================ + */ + + /* continue PES if previous was incomplete */ + if (ty->pes_buf_cnt > 0) { + need = ty->pes_length - ty->pes_buf_cnt; + + ff_dlog(s, "continuing PES header\n"); + /* do we have enough data to complete? */ + if (need >= rec_size) { + /* don't have complete PES hdr; save what we have and return */ + memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + ty->pes_buf_cnt += rec_size; + return 0; + } + + /* we have enough; reconstruct this frame with the new hdr */ + memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, need); + ty->cur_chunk_pos += need; + /* get the PTS out of this PES header (MPEG or AC3) */ + if (ty->audio_type == TIVO_AUDIO_MPEG) { + es_offset1 = find_es_header(ty_MPEGAudioPacket, + ty->pes_buffer, 5); + } else { + es_offset1 = find_es_header(ty_AC3AudioPacket, + ty->pes_buffer, 5); + } + if (es_offset1 < 0) { + ff_dlog(s, "Can't find audio PES header in packet.\n"); + } else { + ty->last_audio_pts = ff_parse_pes_pts( + &ty->pes_buffer[es_offset1 + ty->pts_offset]); + pkt->pts = ty->last_audio_pts; + } + ty->pes_buf_cnt = 0; + + } + if (av_new_packet(pkt, rec_size - need) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size - need); + ty->cur_chunk_pos += rec_size - need; + pkt->stream_index = 1; + + /* S2 DTivo has AC3 packets with 2 padding bytes at end. This is + * not allowed in the AC3 spec and will cause problems. So here + * we try to trim things. */ + /* Also, S1 DTivo has alternating short / long AC3 packets. That + * is, one packet is short (incomplete) and the next packet has + * the first one's missing data, plus all of its own. Strange. */ + if (ty->audio_type == TIVO_AUDIO_AC3 && + ty->tivo_series == TIVO_SERIES2) { + if (ty->ac3_pkt_size + pkt->size > AC3_PKT_LENGTH) { + pkt->size -= 2; + ty->ac3_pkt_size = 0; + } else { + ty->ac3_pkt_size += pkt->size; + } + } + } else if (subrec_type == 0x03) { + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + pkt->stream_index = 1; + /* MPEG Audio with PES Header, either SA or DTiVo */ + /* ================================================ */ + es_offset1 = find_es_header(ty_MPEGAudioPacket, pkt->data, 5); + + /* SA PES Header, No Audio Data */ + /* ================================================ */ + if ((es_offset1 == 0) && (rec_size == 16)) { + ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[SA_PTS_OFFSET]); + if (ty->first_audio_pts == AV_NOPTS_VALUE) + ty->first_audio_pts = ty->last_audio_pts; + av_packet_unref(pkt); + return 0; + } + /* DTiVo Audio with PES Header */ + /* ================================================ */ + + /* Check for complete PES */ + if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) { + /* partial PES header found, nothing else. + * we're done. */ + av_packet_unref(pkt); + return 0; + } + } else if (subrec_type == 0x04) { + /* SA Audio with no PES Header */ + /* ================================================ */ + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + pkt->stream_index = 1; + pkt->pts = ty->last_audio_pts; + } else if (subrec_type == 0x09) { + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size ; + pkt->stream_index = 1; + + /* DTiVo AC3 Audio Data with PES Header */ + /* ================================================ */ + es_offset1 = find_es_header(ty_AC3AudioPacket, pkt->data, 5); + + /* Check for complete PES */ + if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) { + /* partial PES header found, nothing else. we're done. */ + av_packet_unref(pkt); + return 0; + } + /* S2 DTivo has invalid long AC3 packets */ + if (ty->tivo_series == TIVO_SERIES2) { + if (pkt->size > AC3_PKT_LENGTH) { + pkt->size -= 2; + ty->ac3_pkt_size = 0; + } else { + ty->ac3_pkt_size = pkt->size; + } + } + } else { + /* Unsupported/Unknown */ + ty->cur_chunk_pos += rec_size; + return 0; + } + + return 1; +} + +static int ty_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + TYDemuxContext *ty = s->priv_data; + AVIOContext *pb = s->pb; + TyRecHdr *rec; + int64_t rec_size = 0; + int ret = 0; + + if (avio_feof(pb)) + return AVERROR_EOF; + + while (ret <= 0) { + if (!ty->rec_hdrs || ty->first_chunk || ty->cur_rec >= ty->num_recs) { + if (get_chunk(s) < 0 || ty->num_recs <= 0) + return AVERROR_EOF; + } + + rec = &ty->rec_hdrs[ty->cur_rec]; + rec_size = rec->rec_size; + ty->cur_rec++; + + if (rec_size <= 0) + continue; + + if (ty->cur_chunk_pos + rec->rec_size > CHUNK_SIZE) + return AVERROR_INVALIDDATA; + + if (avio_feof(pb)) + return AVERROR_EOF; + + switch (rec->rec_type) { + case VIDEO_ID: + ret = demux_video(s, rec, pkt); + break; + case AUDIO_ID: + ret = demux_audio(s, rec, pkt); + break; + default: + ff_dlog(s, "Invalid record type 0x%02x\n", rec->rec_type); + case 0x01: + case 0x02: + case 0x03: /* TiVo data services */ + case 0x05: /* unknown, but seen regularly */ + ty->cur_chunk_pos += rec->rec_size; + break; + } + } + + return 0; +} + +static int ty_read_close(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + + av_freep(&ty->seq_table); + av_freep(&ty->rec_hdrs); + + return 0; +} + +AVInputFormat ff_ty_demuxer = { + .name = "ty", + .long_name = NULL_IF_CONFIG_SMALL("TiVo TY Stream"), + .priv_data_size = sizeof(TYDemuxContext), + .read_probe = ty_probe, + .read_header = ty_read_header, + .read_packet = ty_read_packet, + .read_close = ty_read_close, + .extensions = "ty,ty+", + .flags = AVFMT_TS_DISCONT, +}; diff --git a/libavformat/udp.c b/libavformat/udp.c index 3835f989c..0dde0353f 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -64,10 +64,6 @@ #include #endif -#ifndef HAVE_PTHREAD_CANCEL -#define HAVE_PTHREAD_CANCEL 0 -#endif - #ifndef IPV6_ADD_MEMBERSHIP #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP diff --git a/libavformat/utils.c b/libavformat/utils.c index 1a7996c4f..2185a6f05 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -32,6 +32,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" +#include "libavutil/thread.h" #include "libavutil/time.h" #include "libavutil/time_internal.h" #include "libavutil/timestamp.h" @@ -55,6 +56,8 @@ #include "libavutil/ffversion.h" const char av_format_ffversion[] = "FFmpeg version " FFMPEG_VERSION; +static AVMutex avformat_mutex = AV_MUTEX_INITIALIZER; + /** * @file * various utility functions for use within FFmpeg @@ -77,6 +80,16 @@ const char *avformat_license(void) return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; } +int ff_lock_avformat(void) +{ + return ff_mutex_lock(&avformat_mutex) ? -1 : 0; +} + +int ff_unlock_avformat(void) +{ + return ff_mutex_unlock(&avformat_mutex) ? -1 : 0; +} + #define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48)) static int is_relative(int64_t ts) { @@ -104,6 +117,7 @@ static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp) return timestamp; } +#if FF_API_FORMAT_GET_SET MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate) MAKE_ACCESSORS(AVStream, stream, char *, recommended_encoder_configuration) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec) @@ -118,11 +132,12 @@ FF_DISABLE_DEPRECATION_WARNINGS MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb) FF_ENABLE_DEPRECATION_WARNINGS #endif +#endif int64_t av_stream_get_end_pts(const AVStream *st) { - if (st->priv_pts) { - return st->priv_pts->val; + if (st->internal->priv_pts) { + return st->internal->priv_pts->val; } else return AV_NOPTS_VALUE; } @@ -215,10 +230,12 @@ static const AVCodec *find_probe_decoder(AVFormatContext *s, const AVStream *st, return codec; } +#if FF_API_FORMAT_GET_SET int av_format_get_probe_score(const AVFormatContext *s) { return s->probe_score; } +#endif /* an arbitrarily chosen "sane" max packet size -- 50M */ #define SANE_CHUNK_SIZE (50000000) @@ -320,6 +337,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, } fmt_id_type[] = { { "aac", AV_CODEC_ID_AAC, AVMEDIA_TYPE_AUDIO }, { "ac3", AV_CODEC_ID_AC3, AVMEDIA_TYPE_AUDIO }, + { "aptx", AV_CODEC_ID_APTX, AVMEDIA_TYPE_AUDIO }, { "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO }, { "dvbsub", AV_CODEC_ID_DVB_SUBTITLE,AVMEDIA_TYPE_SUBTITLE }, { "dvbtxt", AV_CODEC_ID_DVB_TELETEXT,AVMEDIA_TYPE_SUBTITLE }, @@ -1453,6 +1471,7 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) out_pkt.pts = st->parser->pts; out_pkt.dts = st->parser->dts; out_pkt.pos = st->parser->pos; + out_pkt.flags |= pkt->flags & AV_PKT_FLAG_DISCARD; if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) out_pkt.pos = st->parser->frame_offset; @@ -1677,13 +1696,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } st->inject_global_side_data = 0; } - -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - if (!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) - av_packet_merge_side_data(pkt); -FF_ENABLE_DEPRECATION_WARNINGS -#endif } av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata); @@ -1738,10 +1750,11 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) // last dts seen for this stream. if any of packets following // current one had no dts, we will set this to AV_NOPTS_VALUE. int64_t last_dts = next_pkt->dts; + av_assert2(wrap_bits <= 64); while (pktl && next_pkt->pts == AV_NOPTS_VALUE) { if (pktl->pkt.stream_index == next_pkt->stream_index && - (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) { - if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { + av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2ULL << (wrap_bits - 1)) < 0) { + if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2ULL << (wrap_bits - 1))) { // not B-frame next_pkt->pts = pktl->pkt.dts; } @@ -3629,6 +3642,7 @@ FF_ENABLE_DEPRECATION_WARNINGS /* check if one codec still needs to be handled */ for (i = 0; i < ic->nb_streams; i++) { int fps_analyze_framecount = 20; + int count; st = ic->streams[i]; if (!has_codec_parameters(st, NULL)) @@ -3645,14 +3659,18 @@ FF_ENABLE_DEPRECATION_WARNINGS if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) fps_analyze_framecount = 0; /* variable fps and no guess at the real fps */ + count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ? + st->info->codec_info_duration_fields/2 : + st->info->duration_count; if (!(st->r_frame_rate.num && st->avg_frame_rate.num) && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - int count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ? - st->info->codec_info_duration_fields/2 : - st->info->duration_count; if (count < fps_analyze_framecount) break; } + // Look at the first 3 frames if there is evidence of frame delay + // but the decoder delay is not set. + if (st->info->frame_delay_evidence && count < 2 && st->internal->avctx->has_b_frames == 0) + break; if (!st->internal->avctx->extradata && (!st->internal->extract_extradata.inited || st->internal->extract_extradata.bsf) && @@ -3802,10 +3820,13 @@ FF_ENABLE_DEPRECATION_WARNINGS st->info->codec_info_duration_fields += st->parser && st->need_parsing && avctx->ticks_per_frame ==2 ? st->parser->repeat_pict + 1 : 2; } } + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { #if FF_API_R_FRAME_RATE - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ff_rfps_add_frame(ic, st, pkt->dts); #endif + if (pkt->dts != pkt->pts && pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE) + st->info->frame_delay_evidence = 1; + } if (!st->internal->avctx->extradata) { ret = extract_extradata(st, pkt); if (ret < 0) @@ -3882,12 +3903,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } - // close codecs which were opened in try_decode_frame() - for (i = 0; i < ic->nb_streams; i++) { - st = ic->streams[i]; - avcodec_close(st->internal->avctx); - } - ff_rfps_calculate(ic); for (i = 0; i < ic->nb_streams; i++) { @@ -4027,11 +4042,13 @@ FF_ENABLE_DEPRECATION_WARNINGS ret = avcodec_parameters_from_context(st->codecpar, st->internal->avctx); if (ret < 0) goto find_stream_info_err; +#if FF_API_LOWRES // The decoder might reduce the video size by the lowres factor. - if (av_codec_get_lowres(st->internal->avctx) && orig_w) { + if (st->internal->avctx->lowres && orig_w) { st->codecpar->width = orig_w; st->codecpar->height = orig_h; } +#endif } #if FF_API_LAVF_AVCTX @@ -4040,13 +4057,15 @@ FF_DISABLE_DEPRECATION_WARNINGS if (ret < 0) goto find_stream_info_err; +#if FF_API_LOWRES // The old API (AVStream.codec) "requires" the resolution to be adjusted // by the lowres factor. - if (av_codec_get_lowres(st->internal->avctx) && st->internal->avctx->width) { - av_codec_set_lowres(st->codec, av_codec_get_lowres(st->internal->avctx)); + if (st->internal->avctx->lowres && st->internal->avctx->width) { + st->codec->lowres = st->internal->avctx->lowres; st->codec->width = st->internal->avctx->width; st->codec->height = st->internal->avctx->height; } +#endif if (st->codec->codec_tag != MKTAG('t','m','c','d')) { st->codec->time_base = st->internal->avctx->time_base; @@ -4078,6 +4097,7 @@ find_stream_info_err: st = ic->streams[i]; if (st->info) av_freep(&st->info->duration_error); + avcodec_close(ic->streams[i]->internal->avctx); av_freep(&ic->streams[i]->info); av_bsf_free(&ic->streams[i]->internal->extract_extradata.bsf); av_packet_free(&ic->streams[i]->internal->extract_extradata.pkt); @@ -4271,6 +4291,7 @@ static void free_stream(AVStream **pst) av_bsf_free(&st->internal->bsfcs[i]); av_freep(&st->internal->bsfcs); } + av_freep(&st->internal->priv_pts); av_bsf_free(&st->internal->extract_extradata.bsf); av_packet_free(&st->internal->extract_extradata.pkt); } @@ -4290,7 +4311,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_freep(&st->info->duration_error); av_freep(&st->info); av_freep(&st->recommended_encoder_configuration); - av_freep(&st->priv_pts); av_freep(pst); } @@ -4761,10 +4781,10 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, s->time_base = new_tb; #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS - av_codec_set_pkt_timebase(s->codec, new_tb); + s->codec->pkt_timebase = new_tb; FF_ENABLE_DEPRECATION_WARNINGS #endif - av_codec_set_pkt_timebase(s->internal->avctx, new_tb); + s->internal->avctx->pkt_timebase = new_tb; s->pts_wrap_bits = pts_wrap_bits; } @@ -5251,13 +5271,8 @@ int ff_generate_avci_extradata(AVStream *st) return 0; } -#if FF_API_NOCONST_GET_SIDE_DATA -uint8_t *av_stream_get_side_data(AVStream *st, - enum AVPacketSideDataType type, int *size) -#else uint8_t *av_stream_get_side_data(const AVStream *st, enum AVPacketSideDataType type, int *size) -#endif { int i; @@ -5457,6 +5472,11 @@ void ff_format_io_close(AVFormatContext *s, AVIOContext **pb) *pb = NULL; } +int ff_is_http_proto(char *filename) { + const char *proto = avio_find_protocol_name(filename); + return proto ? (!av_strcasecmp(proto, "http") || !av_strcasecmp(proto, "https")) : 0; +} + int ff_parse_creation_time_metadata(AVFormatContext *s, int64_t *timestamp, int return_seconds) { AVDictionaryEntry *entry; diff --git a/libavformat/version.h b/libavformat/version.h index 878917d65..5ced041f0 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,8 +31,8 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here -#define LIBAVFORMAT_VERSION_MAJOR 57 -#define LIBAVFORMAT_VERSION_MINOR 83 +#define LIBAVFORMAT_VERSION_MAJOR 58 +#define LIBAVFORMAT_VERSION_MINOR 3 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -55,47 +55,32 @@ * at once through the bump. This improves the git bisect-ability of the change. * */ -#ifndef FF_API_LAVF_BITEXACT -#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_FRAC -#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_CODEC_TB -#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_URL_FEOF -#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_FMT_RAWPICTURE -#define FF_API_LAVF_FMT_RAWPICTURE (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif #ifndef FF_API_COMPUTE_PKT_FIELDS2 -#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_OLD_OPEN_CALLBACKS -#define FF_API_OLD_OPEN_CALLBACKS (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_OLD_OPEN_CALLBACKS (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_LAVF_AVCTX -#define FF_API_LAVF_AVCTX (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_NOCONST_GET_SIDE_DATA -#define FF_API_NOCONST_GET_SIDE_DATA (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_LAVF_AVCTX (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_HTTP_USER_AGENT -#define FF_API_HTTP_USER_AGENT (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_HTTP_USER_AGENT (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_HLS_WRAP -#define FF_API_HLS_WRAP (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_MERGE_SD -#define FF_API_LAVF_MERGE_SD (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_HLS_WRAP (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_LAVF_KEEPSIDE_FLAG -#define FF_API_LAVF_KEEPSIDE_FLAG (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_LAVF_KEEPSIDE_FLAG (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_OLD_ROTATE_API -#define FF_API_OLD_ROTATE_API (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_OLD_ROTATE_API (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_FORMAT_GET_SET +#define FF_API_FORMAT_GET_SET (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_OLD_AVIO_EOF_0 +#define FF_API_OLD_AVIO_EOF_0 (LIBAVFORMAT_VERSION_MAJOR < 59) #endif diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index b016185a1..e280be4d4 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -822,6 +822,7 @@ static int w64_read_header(AVFormatContext *s) samples = avio_rl64(pb); if (samples > 0) st->duration = samples; + avio_skip(pb, FFALIGN(size, INT64_C(8)) - 32); } else if (!memcmp(guid, ff_w64_guid_data, 16)) { wav->data_end = avio_tell(pb) + size - 24; diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c index adb20cb21..159119d69 100644 --- a/libavformat/wavenc.c +++ b/libavformat/wavenc.c @@ -74,8 +74,6 @@ typedef struct WAVMuxContext { uint32_t peak_num_frames; uint32_t peak_outbuf_size; uint32_t peak_outbuf_bytes; - uint32_t peak_pos_pop; - uint16_t peak_pop; uint8_t *peak_output; int last_duration; int write_bext; @@ -195,7 +193,6 @@ static void peak_write_frame(AVFormatContext *s) { WAVMuxContext *wav = s->priv_data; AVCodecParameters *par = s->streams[0]->codecpar; - int peak_of_peaks; int c; if (!wav->peak_output) @@ -213,12 +210,6 @@ static void peak_write_frame(AVFormatContext *s) wav->peak_maxpos[c] = FFMAX(wav->peak_maxpos[c], wav->peak_maxneg[c]); - peak_of_peaks = FFMAX3(wav->peak_maxpos[c], wav->peak_maxneg[c], - wav->peak_pop); - if (peak_of_peaks > wav->peak_pop) - wav->peak_pos_pop = wav->peak_num_frames; - wav->peak_pop = peak_of_peaks; - if (wav->peak_outbuf_size - wav->peak_outbuf_bytes < wav->peak_format * wav->peak_ppv) { wav->peak_outbuf_size += PEAK_BUFFER_SIZE; @@ -287,7 +278,7 @@ static int peak_write_chunk(AVFormatContext *s) avio_wl32(pb, wav->peak_block_size); /* frames per value */ avio_wl32(pb, par->channels); /* number of channels */ avio_wl32(pb, wav->peak_num_frames); /* number of peak frames */ - avio_wl32(pb, wav->peak_pos_pop); /* audio sample frame index */ + avio_wl32(pb, -1); /* audio sample frame position (not implemented) */ avio_wl32(pb, 128); /* equal to size of header */ avio_write(pb, timestamp, 28); /* ASCII time stamp */ ffio_fill(pb, 0, 60); diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c index 27be5c9c0..301163bdc 100644 --- a/libavformat/wtvdec.c +++ b/libavformat/wtvdec.c @@ -65,7 +65,7 @@ static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset) } /** - * @return bytes read, 0 on end of file, or <0 on error + * @return bytes read, AVERROR_EOF on end of file, or <0 on error */ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) { @@ -76,7 +76,7 @@ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) if (wf->error || pb->error) return -1; if (wf->position >= wf->length || avio_feof(pb)) - return 0; + return AVERROR_EOF; buf_size = FFMIN(buf_size, wf->length - wf->position); while(nread < buf_size) { diff --git a/libavformat/yuv4mpegdec.c b/libavformat/yuv4mpegdec.c index 462b82386..ff0125e4c 100644 --- a/libavformat/yuv4mpegdec.c +++ b/libavformat/yuv4mpegdec.c @@ -126,6 +126,12 @@ static int yuv4_read_header(AVFormatContext *s) pix_fmt = AV_PIX_FMT_YUV444P; } else if (strncmp("mono16", tokstart, 6) == 0) { pix_fmt = AV_PIX_FMT_GRAY16; + } else if (strncmp("mono12", tokstart, 6) == 0) { + pix_fmt = AV_PIX_FMT_GRAY12; + } else if (strncmp("mono10", tokstart, 6) == 0) { + pix_fmt = AV_PIX_FMT_GRAY10; + } else if (strncmp("mono9", tokstart, 5) == 0) { + pix_fmt = AV_PIX_FMT_GRAY9; } else if (strncmp("mono", tokstart, 4) == 0) { pix_fmt = AV_PIX_FMT_GRAY8; } else { diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c index b4dc6e9ef..44f40bbad 100644 --- a/libavformat/yuv4mpegenc.c +++ b/libavformat/yuv4mpegenc.c @@ -69,6 +69,15 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) case AV_PIX_FMT_GRAY8: colorspace = " Cmono"; break; + case AV_PIX_FMT_GRAY9: + colorspace = " Cmono9"; + break; + case AV_PIX_FMT_GRAY10: + colorspace = " Cmono10"; + break; + case AV_PIX_FMT_GRAY12: + colorspace = " Cmono12"; + break; case AV_PIX_FMT_GRAY16: colorspace = " Cmono16"; break; @@ -184,6 +193,9 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV444P: break; + case AV_PIX_FMT_GRAY9: + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P9: case AV_PIX_FMT_YUV422P9: @@ -213,7 +225,8 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) ptr += frame->linesize[0]; } - if (st->codecpar->format != AV_PIX_FMT_GRAY8 && + if (st->codecpar->format != AV_PIX_FMT_GRAY8 && st->codecpar->format != AV_PIX_FMT_GRAY9 && + st->codecpar->format != AV_PIX_FMT_GRAY10 && st->codecpar->format != AV_PIX_FMT_GRAY12 && st->codecpar->format != AV_PIX_FMT_GRAY16) { // Adjust for smaller Cb and Cr planes av_pix_fmt_get_chroma_sub_sample(st->codecpar->format, &h_chroma_shift, @@ -255,11 +268,14 @@ static int yuv4_write_header(AVFormatContext *s) "stream, some mjpegtools might not work.\n"); break; case AV_PIX_FMT_GRAY8: - case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV444P: break; + case AV_PIX_FMT_GRAY9: + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P9: case AV_PIX_FMT_YUV422P9: case AV_PIX_FMT_YUV444P9: @@ -291,7 +307,8 @@ static int yuv4_write_header(AVFormatContext *s) "yuv444p10, yuv422p10, yuv420p10, " "yuv444p12, yuv422p12, yuv420p12, " "yuv444p14, yuv422p14, yuv420p14, " - "yuv444p16, yuv422p16, yuv420p16 " + "yuv444p16, yuv422p16, yuv420p16, " + "gray9, gray10, gray12 " "and gray16 pixel formats. " "Use -pix_fmt to select one.\n"); return AVERROR(EIO); diff --git a/libavresample/avresample.h b/libavresample/avresample.h index 193443e2a..5ac9adb44 100644 --- a/libavresample/avresample.h +++ b/libavresample/avresample.h @@ -105,22 +105,31 @@ typedef struct AVAudioResampleContext AVAudioResampleContext; -/** Mixing Coefficient Types */ -enum AVMixCoeffType { +/** + * @deprecated use libswresample + * + * Mixing Coefficient Types */ +enum attribute_deprecated AVMixCoeffType { AV_MIX_COEFF_TYPE_Q8, /** 16-bit 8.8 fixed-point */ AV_MIX_COEFF_TYPE_Q15, /** 32-bit 17.15 fixed-point */ AV_MIX_COEFF_TYPE_FLT, /** floating-point */ AV_MIX_COEFF_TYPE_NB, /** Number of coeff types. Not part of ABI */ }; -/** Resampling Filter Types */ -enum AVResampleFilterType { +/** + * @deprecated use libswresample + * + * Resampling Filter Types */ +enum attribute_deprecated AVResampleFilterType { AV_RESAMPLE_FILTER_TYPE_CUBIC, /**< Cubic */ AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */ AV_RESAMPLE_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */ }; -enum AVResampleDitherMethod { +/** + * @deprecated use libswresample + */ +enum attribute_deprecated AVResampleDitherMethod { AV_RESAMPLE_DITHER_NONE, /**< Do not use dithering */ AV_RESAMPLE_DITHER_RECTANGULAR, /**< Rectangular Dither */ AV_RESAMPLE_DITHER_TRIANGULAR, /**< Triangular Dither*/ @@ -130,22 +139,37 @@ enum AVResampleDitherMethod { }; /** + * + * @deprecated use libswresample + * * Return the LIBAVRESAMPLE_VERSION_INT constant. */ +attribute_deprecated unsigned avresample_version(void); /** + * + * @deprecated use libswresample + * * Return the libavresample build-time configuration. * @return configure string */ +attribute_deprecated const char *avresample_configuration(void); /** + * + * @deprecated use libswresample + * * Return the libavresample license. */ +attribute_deprecated const char *avresample_license(void); /** + * + * @deprecated use libswresample + * * Get the AVClass for AVAudioResampleContext. * * Can be used in combination with AV_OPT_SEARCH_FAKE_OBJ for examining options @@ -155,16 +179,24 @@ const char *avresample_license(void); * * @return AVClass for AVAudioResampleContext */ +attribute_deprecated const AVClass *avresample_get_class(void); /** + * + * @deprecated use libswresample + * * Allocate AVAudioResampleContext and set options. * * @return allocated audio resample context, or NULL on failure */ +attribute_deprecated AVAudioResampleContext *avresample_alloc_context(void); /** + * + * @deprecated use libswresample + * * Initialize AVAudioResampleContext. * @note The context must be configured using the AVOption API. * @note The fields "in_channel_layout", "out_channel_layout", @@ -178,17 +210,25 @@ AVAudioResampleContext *avresample_alloc_context(void); * @param avr audio resample context * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_open(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Check whether an AVAudioResampleContext is open or closed. * * @param avr AVAudioResampleContext to check * @return 1 if avr is open, 0 if avr is closed. */ +attribute_deprecated int avresample_is_open(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Close AVAudioResampleContext. * * This closes the context, but it does not change the parameters. The context @@ -201,18 +241,26 @@ int avresample_is_open(AVAudioResampleContext *avr); * * @param avr audio resample context */ +attribute_deprecated void avresample_close(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Free AVAudioResampleContext and associated AVOption values. * * This also calls avresample_close() before freeing. * * @param avr audio resample context */ +attribute_deprecated void avresample_free(AVAudioResampleContext **avr); /** + * + * @deprecated use libswresample + * * Generate a channel mixing matrix. * * This function is the one used internally by libavresample for building the @@ -234,12 +282,16 @@ void avresample_free(AVAudioResampleContext **avr); * @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, double center_mix_level, double surround_mix_level, double lfe_mix_level, int normalize, double *matrix, int stride, enum AVMatrixEncoding matrix_encoding); /** + * + * @deprecated use libswresample + * * Get the current channel mixing matrix. * * If no custom matrix has been previously set or the AVAudioResampleContext is @@ -251,10 +303,14 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, * @param stride distance between adjacent input channels in the matrix array * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, int stride); /** + * + * @deprecated use libswresample + * * Set channel mixing matrix. * * Allows for setting a custom mixing matrix, overriding the default matrix @@ -272,10 +328,14 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, * @param stride distance between adjacent input channels in the matrix array * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, int stride); /** + * + * @deprecated use libswresample + * * Set a customized input channel mapping. * * This function can only be called when the allocated context is not open. @@ -302,10 +362,14 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, * @param channel_map customized input channel mapping * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_set_channel_mapping(AVAudioResampleContext *avr, const int *channel_map); /** + * + * @deprecated use libswresample + * * Set compensation for resampling. * * This can be called anytime after avresample_open(). If resampling is not @@ -318,10 +382,14 @@ int avresample_set_channel_mapping(AVAudioResampleContext *avr, * @param compensation_distance compensation distance, in samples * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, int compensation_distance); /** + * + * @deprecated use libswresample + * * Provide the upper bound on the number of samples the configured * conversion would output. * @@ -331,10 +399,13 @@ int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, * @return number of samples or AVERROR(EINVAL) if the value * would exceed INT_MAX */ - +attribute_deprecated int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples); /** + * + * @deprecated use libswresample + * * Convert input samples and write them to the output FIFO. * * The upper bound on the number of output samples can be obtained through @@ -376,12 +447,16 @@ int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples); * not including converted samples added to the internal * output FIFO */ +attribute_deprecated int avresample_convert(AVAudioResampleContext *avr, uint8_t **output, int out_plane_size, int out_samples, uint8_t * const *input, int in_plane_size, int in_samples); /** + * + * @deprecated use libswresample + * * Return the number of samples currently in the resampling delay buffer. * * When resampling, there may be a delay between the input and output. Any @@ -394,9 +469,13 @@ int avresample_convert(AVAudioResampleContext *avr, uint8_t **output, * @param avr audio resample context * @return number of samples currently in the resampling delay buffer */ +attribute_deprecated int avresample_get_delay(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Return the number of available samples in the output FIFO. * * During conversion, if the user does not specify an output buffer or @@ -411,9 +490,13 @@ int avresample_get_delay(AVAudioResampleContext *avr); * @param avr audio resample context * @return number of samples available for reading */ +attribute_deprecated int avresample_available(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Read samples from the output FIFO. * * During conversion, if the user does not specify an output buffer or @@ -430,9 +513,13 @@ int avresample_available(AVAudioResampleContext *avr); * @param nb_samples number of samples to read from the FIFO * @return the number of samples written to output */ +attribute_deprecated int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples); /** + * + * @deprecated use libswresample + * * 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. @@ -476,10 +563,14 @@ int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_sample * @return 0 on success, AVERROR on failure or nonmatching * configuration. */ +attribute_deprecated int avresample_convert_frame(AVAudioResampleContext *avr, AVFrame *output, AVFrame *input); /** + * + * @deprecated use libswresample + * * Configure or reconfigure the AVAudioResampleContext using the information * provided by the AVFrames. * @@ -494,6 +585,7 @@ int avresample_convert_frame(AVAudioResampleContext *avr, * @param in input AVFrame * @return 0 on success, AVERROR on failure. */ +attribute_deprecated int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in); /** diff --git a/libavresample/tests/.gitignore b/libavresample/tests/.gitignore new file mode 100644 index 000000000..1e15871d5 --- /dev/null +++ b/libavresample/tests/.gitignore @@ -0,0 +1 @@ +/avresample diff --git a/libavresample/version.h b/libavresample/version.h index 20c78c74d..d5d3ea82b 100644 --- a/libavresample/version.h +++ b/libavresample/version.h @@ -27,8 +27,8 @@ #include "libavutil/version.h" -#define LIBAVRESAMPLE_VERSION_MAJOR 3 -#define LIBAVRESAMPLE_VERSION_MINOR 7 +#define LIBAVRESAMPLE_VERSION_MAJOR 4 +#define LIBAVRESAMPLE_VERSION_MINOR 0 #define LIBAVRESAMPLE_VERSION_MICRO 0 #define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \ diff --git a/libavutil/.gitignore b/libavutil/.gitignore new file mode 100644 index 000000000..4dc746677 --- /dev/null +++ b/libavutil/.gitignore @@ -0,0 +1,2 @@ +/avconfig.h +/ffversion.h diff --git a/libavutil/Makefile b/libavutil/Makefile index 65e285a70..d7474f59e 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -37,6 +37,7 @@ HEADERS = adler32.h \ hwcontext_drm.h \ hwcontext_dxva2.h \ hwcontext_qsv.h \ + hwcontext_mediacodec.h \ hwcontext_vaapi.h \ hwcontext_videotoolbox.h \ hwcontext_vdpau.h \ @@ -79,8 +80,6 @@ HEADERS = adler32.h \ HEADERS-$(CONFIG_LZO) += lzo.h -HEADERS-$(CONFIG_OPENCL) += opencl.h - ARCH_HEADERS = bswap.h \ intmath.h \ intreadwrite.h \ @@ -156,18 +155,17 @@ OBJS = adler32.o \ xtea.o \ tea.o \ -OBJS-$(!HAVE_ATOMICS_NATIVE) += atomic.o \ - OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o OBJS-$(CONFIG_QSV) += hwcontext_qsv.o OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o OBJS-$(CONFIG_LZO) += lzo.o -OBJS-$(CONFIG_OPENCL) += opencl.o opencl_internal.o +OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o +OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o OBJS += $(COMPAT_OBJS:%=../compat/%) @@ -179,18 +177,14 @@ SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.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 -SKIPHEADERS-$(HAVE_ATOMICS_GCC) += atomic_gcc.h -SKIPHEADERS-$(HAVE_ATOMICS_SUNCC) += atomic_suncc.h -SKIPHEADERS-$(HAVE_ATOMICS_WIN32) += atomic_win32.h -SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h TESTPROGS = adler32 \ aes \ aes_ctr \ - atomic \ audio_fifo \ avstring \ base64 \ diff --git a/libavutil/aarch64/asm.S b/libavutil/aarch64/asm.S index 428972942..fd32bf784 100644 --- a/libavutil/aarch64/asm.S +++ b/libavutil/aarch64/asm.S @@ -23,7 +23,7 @@ #ifdef __ELF__ # define ELF #else -# define ELF # +# define ELF # #endif #if HAVE_AS_FUNC @@ -82,6 +82,15 @@ ELF .size \name, . - \name adrp \rd, \val+(\offset)@PAGE add \rd, \rd, \val+(\offset)@PAGEOFF .endif +#elif CONFIG_PIC && defined(_WIN32) + .if \offset < 0 + adrp \rd, \val + add \rd, \rd, :lo12:\val + sub \rd, \rd, -(\offset) + .else + adrp \rd, \val+(\offset) + add \rd, \rd, :lo12:\val+(\offset) + .endif #elif CONFIG_PIC adrp \rd, \val+(\offset) add \rd, \rd, :lo12:\val+(\offset) diff --git a/libavutil/arm/asm.S b/libavutil/arm/asm.S index 7d33a64fa..eb689a103 100644 --- a/libavutil/arm/asm.S +++ b/libavutil/arm/asm.S @@ -46,6 +46,7 @@ # define FPU @ #endif +#if HAVE_AS_ARCH_DIRECTIVE #if HAVE_NEON .arch armv7-a #elif HAVE_ARMV6T2 @@ -55,6 +56,7 @@ #elif HAVE_ARMV5TE .arch armv5te #endif +#endif #if HAVE_AS_OBJECT_ARCH ELF .object_arch armv4 #endif diff --git a/libavutil/arm/float_dsp_init_vfp.c b/libavutil/arm/float_dsp_init_vfp.c index e15abf3f5..05873e7e3 100644 --- a/libavutil/arm/float_dsp_init_vfp.c +++ b/libavutil/arm/float_dsp_init_vfp.c @@ -36,11 +36,11 @@ void ff_butterflies_float_vfp(float *av_restrict v1, float *av_restrict v2, int av_cold void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags) { - if (!have_vfpv3(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_vfpv3(cpu_flags)) + if (have_vfp_vm(cpu_flags)) fdsp->butterflies_float = ff_butterflies_float_vfp; } diff --git a/libavutil/arm/intmath.h b/libavutil/arm/intmath.h index 65e42c573..5311a7d52 100644 --- a/libavutil/arm/intmath.h +++ b/libavutil/arm/intmath.h @@ -94,6 +94,22 @@ static av_always_inline int av_sat_dadd32_arm(int a, int 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 diff --git a/libavutil/atomic.c b/libavutil/atomic.c deleted file mode 100644 index 64cff2576..000000000 --- a/libavutil/atomic.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 "atomic.h" - -#if !HAVE_ATOMICS_NATIVE - -#if HAVE_PTHREADS - -#include - -static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER; - -int avpriv_atomic_int_get(volatile int *ptr) -{ - int res; - - pthread_mutex_lock(&atomic_lock); - res = *ptr; - pthread_mutex_unlock(&atomic_lock); - - return res; -} - -void avpriv_atomic_int_set(volatile int *ptr, int val) -{ - pthread_mutex_lock(&atomic_lock); - *ptr = val; - pthread_mutex_unlock(&atomic_lock); -} - -int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc) -{ - int res; - - pthread_mutex_lock(&atomic_lock); - *ptr += inc; - res = *ptr; - pthread_mutex_unlock(&atomic_lock); - - return res; -} - -void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval) -{ - void *ret; - pthread_mutex_lock(&atomic_lock); - ret = *ptr; - if (ret == oldval) - *ptr = newval; - pthread_mutex_unlock(&atomic_lock); - return ret; -} - -#elif !HAVE_THREADS - -int avpriv_atomic_int_get(volatile int *ptr) -{ - return *ptr; -} - -void avpriv_atomic_int_set(volatile int *ptr, int val) -{ - *ptr = val; -} - -int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc) -{ - *ptr += inc; - return *ptr; -} - -void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval) -{ - if (*ptr == oldval) { - *ptr = newval; - return oldval; - } - return *ptr; -} - -#else /* HAVE_THREADS */ - -/* This should never trigger, unless a new threading implementation - * without correct atomics dependencies in configure or a corresponding - * atomics implementation is added. */ -#error "Threading is enabled, but there is no implementation of atomic operations available" - -#endif /* HAVE_PTHREADS */ - -#endif /* !HAVE_ATOMICS_NATIVE */ diff --git a/libavutil/atomic.h b/libavutil/atomic.h deleted file mode 100644 index 15906d24c..000000000 --- a/libavutil/atomic.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 - */ - -#ifndef AVUTIL_ATOMIC_H -#define AVUTIL_ATOMIC_H - -#include "config.h" - -#if HAVE_ATOMICS_NATIVE - -#if HAVE_ATOMICS_GCC -#include "atomic_gcc.h" -#elif HAVE_ATOMICS_WIN32 -#include "atomic_win32.h" -#elif HAVE_ATOMICS_SUNCC -#include "atomic_suncc.h" -#endif - -#else - -/** - * Load the current value stored in an atomic integer. - * - * @param ptr atomic integer - * @return the current value of the atomic integer - * @note This acts as a memory barrier. - */ -int avpriv_atomic_int_get(volatile int *ptr); - -/** - * Store a new value in an atomic integer. - * - * @param ptr atomic integer - * @param val the value to store in the atomic integer - * @note This acts as a memory barrier. - */ -void avpriv_atomic_int_set(volatile int *ptr, int val); - -/** - * Add a value to an atomic integer. - * - * @param ptr atomic integer - * @param inc the value to add to the atomic integer (may be negative) - * @return the new value of the atomic integer. - * @note This does NOT act as a memory barrier. This is primarily - * intended for reference counting. - */ -int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc); - -/** - * Atomic pointer compare and swap. - * - * @param ptr pointer to the pointer to operate on - * @param oldval do the swap if the current value of *ptr equals to oldval - * @param newval value to replace *ptr with - * @return the value of *ptr before comparison - */ -void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval); - -#endif /* HAVE_ATOMICS_NATIVE */ - -#endif /* AVUTIL_ATOMIC_H */ diff --git a/libavutil/atomic_gcc.h b/libavutil/atomic_gcc.h deleted file mode 100644 index 2bb43c3ce..000000000 --- a/libavutil/atomic_gcc.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 - */ - -#ifndef AVUTIL_ATOMIC_GCC_H -#define AVUTIL_ATOMIC_GCC_H - -#include - -#include "atomic.h" - -#define avpriv_atomic_int_get atomic_int_get_gcc -static inline int atomic_int_get_gcc(volatile int *ptr) -{ - __sync_synchronize(); - return *ptr; -} - -#define avpriv_atomic_int_set atomic_int_set_gcc -static inline void atomic_int_set_gcc(volatile int *ptr, int val) -{ - *ptr = val; - __sync_synchronize(); -} - -#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_gcc -static inline int atomic_int_add_and_fetch_gcc(volatile int *ptr, int inc) -{ - return __sync_add_and_fetch(ptr, inc); -} - -#define avpriv_atomic_ptr_cas atomic_ptr_cas_gcc -static inline void *atomic_ptr_cas_gcc(void * volatile *ptr, - void *oldval, void *newval) -{ -#ifdef __ARMCC_VERSION - // armcc will throw an error if ptr is not an integer type - volatile uintptr_t *tmp = (volatile uintptr_t*)ptr; - return (void*)__sync_val_compare_and_swap(tmp, oldval, newval); -#else - return __sync_val_compare_and_swap(ptr, oldval, newval); -#endif -} - -#endif /* AVUTIL_ATOMIC_GCC_H */ diff --git a/libavutil/atomic_suncc.h b/libavutil/atomic_suncc.h deleted file mode 100644 index a75a37b47..000000000 --- a/libavutil/atomic_suncc.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_ATOMIC_SUNCC_H -#define AVUTIL_ATOMIC_SUNCC_H - -#include -#include - -#include "atomic.h" - -#define avpriv_atomic_int_get atomic_int_get_suncc -static inline int atomic_int_get_suncc(volatile int *ptr) -{ - __machine_rw_barrier(); - return *ptr; -} - -#define avpriv_atomic_int_set atomic_int_set_suncc -static inline void atomic_int_set_suncc(volatile int *ptr, int val) -{ - *ptr = val; - __machine_rw_barrier(); -} - -#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_suncc -static inline int atomic_int_add_and_fetch_suncc(volatile int *ptr, int inc) -{ - return atomic_add_int_nv(ptr, inc); -} - -#define avpriv_atomic_ptr_cas atomic_ptr_cas_suncc -static inline void *atomic_ptr_cas_suncc(void * volatile *ptr, - void *oldval, void *newval) -{ - return atomic_cas_ptr(ptr, oldval, newval); -} - -#endif /* AVUTIL_ATOMIC_SUNCC_H */ diff --git a/libavutil/atomic_win32.h b/libavutil/atomic_win32.h deleted file mode 100644 index f7299336f..000000000 --- a/libavutil/atomic_win32.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - */ - -#ifndef AVUTIL_ATOMIC_WIN32_H -#define AVUTIL_ATOMIC_WIN32_H - -#define WIN32_LEAN_AND_MEAN -#include - -#define avpriv_atomic_int_get atomic_int_get_win32 -static inline int atomic_int_get_win32(volatile int *ptr) -{ - MemoryBarrier(); - return *ptr; -} - -#define avpriv_atomic_int_set atomic_int_set_win32 -static inline void atomic_int_set_win32(volatile int *ptr, int val) -{ - *ptr = val; - MemoryBarrier(); -} - -#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_win32 -static inline int atomic_int_add_and_fetch_win32(volatile int *ptr, int inc) -{ - return inc + InterlockedExchangeAdd(ptr, inc); -} - -#define avpriv_atomic_ptr_cas atomic_ptr_cas_win32 -static inline void *atomic_ptr_cas_win32(void * volatile *ptr, - void *oldval, void *newval) -{ - return InterlockedCompareExchangePointer(ptr, newval, oldval); -} - -#endif /* AVUTIL_ATOMIC_WIN32_H */ diff --git a/libavutil/attributes.h b/libavutil/attributes.h index 54d190111..ced108aa2 100644 --- a/libavutil/attributes.h +++ b/libavutil/attributes.h @@ -66,19 +66,19 @@ # define av_noinline #endif -#if AV_GCC_VERSION_AT_LEAST(3,1) +#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) +#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) +#if AV_GCC_VERSION_AT_LEAST(4,3) || defined(__clang__) # define av_cold __attribute__((cold)) #else # define av_cold @@ -138,19 +138,19 @@ # define av_used #endif -#if AV_GCC_VERSION_AT_LEAST(3,3) +#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(__INTEL_COMPILER) && !defined(__clang__) +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER) # define av_uninit(x) x=x #else # define av_uninit(x) x #endif -#ifdef __GNUC__ +#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 @@ -158,7 +158,7 @@ # define av_printf_format(fmtpos, attrpos) #endif -#if AV_GCC_VERSION_AT_LEAST(2,5) +#if AV_GCC_VERSION_AT_LEAST(2,5) || defined(__clang__) # define av_noreturn __attribute__((noreturn)) #else # define av_noreturn diff --git a/libavutil/common.h b/libavutil/common.h index 8142b31fd..5e0382827 100644 --- a/libavutil/common.h +++ b/libavutil/common.h @@ -260,13 +260,37 @@ static av_always_inline int av_sat_add32_c(int a, int b) * * @param a first value * @param b value doubled and added to a - * @return sum with signed saturation + * @return sum sat(a + sat(2*b)) with signed saturation */ static av_always_inline int av_sat_dadd32_c(int a, int b) { return av_sat_add32(a, av_sat_add32(b, b)); } +/** + * Subtract two signed 32-bit values with saturation. + * + * @param a one value + * @param b another value + * @return difference with signed saturation + */ +static av_always_inline int av_sat_sub32_c(int a, int b) +{ + return av_clipl_int32((int64_t)a - b); +} + +/** + * Subtract a doubled value from another value with saturation at both stages. + * + * @param a first value + * @param b value doubled and subtracted from a + * @return difference sat(a - sat(2*b)) with signed saturation + */ +static av_always_inline int av_sat_dsub32_c(int a, int b) +{ + return av_sat_sub32(a, av_sat_add32(b, b)); +} + /** * Clip a float value into the amin-amax range. * @param a value to clip @@ -513,6 +537,12 @@ static av_always_inline av_const int av_parity_c(uint32_t v) #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 diff --git a/libavutil/cpu.c b/libavutil/cpu.c index c8401b825..6548cc304 100644 --- a/libavutil/cpu.c +++ b/libavutil/cpu.c @@ -80,7 +80,8 @@ void av_force_cpu_flags(int arg){ AV_CPU_FLAG_XOP | AV_CPU_FLAG_FMA3 | AV_CPU_FLAG_FMA4 | - AV_CPU_FLAG_AVX2 )) + 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; @@ -126,6 +127,7 @@ int av_parse_cpu_flags(const char *s) #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 @@ -154,6 +156,7 @@ int av_parse_cpu_flags(const char *s) { "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" }, @@ -216,6 +219,7 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) { "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 diff --git a/libavutil/cpu.h b/libavutil/cpu.h index 9e5d40aff..8bb9eb606 100644 --- a/libavutil/cpu.h +++ b/libavutil/cpu.h @@ -55,6 +55,7 @@ #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 diff --git a/libavutil/crc.c b/libavutil/crc.c index 495732b16..d44550c9c 100644 --- a/libavutil/crc.c +++ b/libavutil/crc.c @@ -20,6 +20,8 @@ #include "config.h" +#include "thread.h" +#include "avassert.h" #include "bswap.h" #include "common.h" #include "crc.h" @@ -291,20 +293,24 @@ static const AVCRC av_crc_table[AV_CRC_MAX][257] = { #else #define CRC_TABLE_SIZE 1024 #endif -static struct { - uint8_t le; - uint8_t bits; - uint32_t poly; -} av_crc_table_params[AV_CRC_MAX] = { - [AV_CRC_8_ATM] = { 0, 8, 0x07 }, - [AV_CRC_16_ANSI] = { 0, 16, 0x8005 }, - [AV_CRC_16_CCITT] = { 0, 16, 0x1021 }, - [AV_CRC_24_IEEE] = { 0, 24, 0x864CFB }, - [AV_CRC_32_IEEE] = { 0, 32, 0x04C11DB7 }, - [AV_CRC_32_IEEE_LE] = { 1, 32, 0xEDB88320 }, - [AV_CRC_16_ANSI_LE] = { 1, 16, 0xA001 }, -}; 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_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) @@ -343,13 +349,16 @@ int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) const AVCRC *av_crc_get_table(AVCRCId crc_id) { #if !CONFIG_HARDCODED_TABLES - if (!av_crc_table[crc_id][FF_ARRAY_ELEMS(av_crc_table[crc_id]) - 1]) - if (av_crc_init(av_crc_table[crc_id], - av_crc_table_params[crc_id].le, - av_crc_table_params[crc_id].bits, - av_crc_table_params[crc_id].poly, - sizeof(av_crc_table[crc_id])) < 0) - return NULL; + switch (crc_id) { + case AV_CRC_8_ATM: CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM); 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]; } diff --git a/libavutil/crc.h b/libavutil/crc.h index 2a1b0d762..fe9a7c8fc 100644 --- a/libavutil/crc.h +++ b/libavutil/crc.h @@ -53,11 +53,7 @@ typedef enum { 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 */ -#if FF_API_CRC_BIG_TABLE - AV_CRC_24_IEEE = 12, -#else AV_CRC_24_IEEE, -#endif /* FF_API_CRC_BIG_TABLE */ AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ }AVCRCId; diff --git a/libavutil/eval.c b/libavutil/eval.c index b5f4ea240..5da9a6d83 100644 --- a/libavutil/eval.c +++ b/libavutil/eval.c @@ -57,7 +57,14 @@ typedef struct Parser { double *var; } Parser; -static const AVClass eval_class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) }; +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; diff --git a/libavutil/file.c b/libavutil/file.c index 7bdf6cde8..24a86c3f3 100644 --- a/libavutil/file.c +++ b/libavutil/file.c @@ -42,8 +42,12 @@ typedef struct FileLogContext { } FileLogContext; static const AVClass file_log_ctx_class = { - "FILE", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, - offsetof(FileLogContext, log_offset), offsetof(FileLogContext, log_ctx) + .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, diff --git a/libavutil/file_open.c b/libavutil/file_open.c index 34070d933..a8da28358 100644 --- a/libavutil/file_open.c +++ b/libavutil/file_open.c @@ -29,7 +29,7 @@ #include #endif -#if defined(_WIN32) && !defined(__MINGW32CE__) +#ifdef _WIN32 #undef open #undef lseek #undef stat @@ -99,8 +99,12 @@ typedef struct FileLogContext { } FileLogContext; static const AVClass file_log_ctx_class = { - "TEMPFILE", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, - offsetof(FileLogContext, log_offset), offsetof(FileLogContext, log_ctx) + .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) diff --git a/libavutil/frame.c b/libavutil/frame.c index d5fd2932e..662a7e5ab 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -31,6 +31,7 @@ static AVFrameSideData *frame_new_side_data(AVFrame *frame, enum AVFrameSideDataType type, AVBufferRef *buf); +#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) @@ -42,14 +43,13 @@ 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)) -AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame) {return &frame->metadata;}; - #if FF_API_FRAME_QP int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int qp_type) { @@ -383,12 +383,17 @@ 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; } @@ -524,6 +529,7 @@ void av_frame_unref(AVFrame *frame) av_buffer_unref(&frame->hw_frames_ctx); av_buffer_unref(&frame->opaque_ref); + av_buffer_unref(&frame->private_ref); get_frame_defaults(frame); } diff --git a/libavutil/frame.h b/libavutil/frame.h index abe4f4fd1..d54bd9a35 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -563,39 +563,77 @@ typedef struct AVFrame { /** * @} */ + + /** + * 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); -AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); #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. diff --git a/libavutil/hmac.h b/libavutil/hmac.h index 576a0a4fb..412e95071 100644 --- a/libavutil/hmac.h +++ b/libavutil/hmac.h @@ -35,7 +35,7 @@ enum AVHMACType { AV_HMAC_SHA1, AV_HMAC_SHA224, AV_HMAC_SHA256, - AV_HMAC_SHA384 = 12, + AV_HMAC_SHA384, AV_HMAC_SHA512, }; diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c index 048e82126..31ac12807 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c @@ -41,6 +41,9 @@ static const HWContextType * const hw_table[] = { #if CONFIG_DXVA2 &ff_hwcontext_type_dxva2, #endif +#if CONFIG_OPENCL + &ff_hwcontext_type_opencl, +#endif #if CONFIG_QSV &ff_hwcontext_type_qsv, #endif @@ -52,6 +55,9 @@ static const HWContextType * const hw_table[] = { #endif #if CONFIG_VIDEOTOOLBOX &ff_hwcontext_type_videotoolbox, +#endif +#if CONFIG_MEDIACODEC + &ff_hwcontext_type_mediacodec, #endif NULL, }; @@ -61,10 +67,12 @@ static const char *const hw_type_names[] = { [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) @@ -79,7 +87,8 @@ enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name) const char *av_hwdevice_get_type_name(enum AVHWDeviceType type) { - if (type >= 0 && type < FF_ARRAY_ELEMS(hw_type_names)) + if (type > AV_HWDEVICE_TYPE_NONE && + type < FF_ARRAY_ELEMS(hw_type_names)) return hw_type_names[type]; else return NULL; @@ -212,19 +221,16 @@ static void hwframe_ctx_free(void *opaque, uint8_t *data) { AVHWFramesContext *ctx = (AVHWFramesContext*)data; - if (ctx->internal->source_frames) { - av_buffer_unref(&ctx->internal->source_frames); + if (ctx->internal->pool_internal) + av_buffer_pool_uninit(&ctx->internal->pool_internal); - } else { - 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->internal->hw_type->frames_uninit) - ctx->internal->hw_type->frames_uninit(ctx); + if (ctx->free) + ctx->free(ctx); - if (ctx->free) - ctx->free(ctx); - } + av_buffer_unref(&ctx->internal->source_frames); av_buffer_unref(&ctx->device_ref); diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h index 03334e20e..f5a4b6238 100644 --- a/libavutil/hwcontext.h +++ b/libavutil/hwcontext.h @@ -25,15 +25,17 @@ #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_NONE, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DRM, + AV_HWDEVICE_TYPE_OPENCL, + AV_HWDEVICE_TYPE_MEDIACODEC, }; typedef struct AVHWDeviceInternal AVHWDeviceInternal; diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c index dfb67bc94..37827a770 100644 --- a/libavutil/hwcontext_cuda.c +++ b/libavutil/hwcontext_cuda.c @@ -336,7 +336,7 @@ static int cuda_device_init(AVHWDeviceContext *ctx) } if (!hwctx->internal->cuda_dl) { - ret = cuda_load_functions(&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; diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c index 52683b92c..2f97156a5 100644 --- a/libavutil/hwcontext_d3d11va.c +++ b/libavutil/hwcontext_d3d11va.c @@ -123,6 +123,7 @@ static void d3d11va_frames_uninit(AVHWFramesContext *ctx) 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) @@ -457,20 +458,31 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) { AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; - if (device_hwctx->device) + if (device_hwctx->device) { ID3D11Device_Release(device_hwctx->device); + device_hwctx->device = NULL; + } - if (device_hwctx->device_context) + if (device_hwctx->device_context) { ID3D11DeviceContext_Release(device_hwctx->device_context); + device_hwctx->device_context = NULL; + } - if (device_hwctx->video_device) + if (device_hwctx->video_device) { ID3D11VideoDevice_Release(device_hwctx->video_device); + device_hwctx->video_device = NULL; + } - if (device_hwctx->video_context) + if (device_hwctx->video_context) { ID3D11VideoContext_Release(device_hwctx->video_context); + device_hwctx->video_context = NULL; + } - if (device_hwctx->lock == d3d11va_default_lock) + 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, @@ -514,8 +526,15 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, 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) + if (pAdapter) { + DXGI_ADAPTER_DESC2 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); + } IDXGIAdapter_Release(pAdapter); + } if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr); return AVERROR_UNKNOWN; diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h index 98db7ce34..9f91e9b1b 100644 --- a/libavutil/hwcontext_d3d11va.h +++ b/libavutil/hwcontext_d3d11va.h @@ -37,6 +37,7 @@ */ #include +#include /** * This struct is allocated as AVHWDeviceContext.hwctx diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c index 2ddd4be7b..665c2d6d7 100644 --- a/libavutil/hwcontext_dxva2.c +++ b/libavutil/hwcontext_dxva2.c @@ -485,7 +485,12 @@ static int dxva2_device_create9ex(AVHWDeviceContext *ctx, UINT adapter) if (FAILED(hr)) return AVERROR_UNKNOWN; - IDirect3D9Ex_GetAdapterDisplayModeEx(d3d9ex, adapter, &modeex, NULL); + modeex.Size = sizeof(D3DDISPLAYMODEEX); + hr = IDirect3D9Ex_GetAdapterDisplayModeEx(d3d9ex, adapter, &modeex, NULL); + if (FAILED(hr)) { + IDirect3D9Ex_Release(d3d9ex); + return AVERROR_UNKNOWN; + } d3dpp.BackBufferFormat = modeex.Format; diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h index 2d75d3db0..332062dda 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -161,9 +161,11 @@ 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/libavutil/hwcontext_mediacodec.c b/libavutil/hwcontext_mediacodec.c new file mode 100644 index 000000000..b0d8993e1 --- /dev/null +++ b/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/libavfilter/opencl_allkernels.h b/libavutil/hwcontext_mediacodec.h similarity index 63% rename from libavfilter/opencl_allkernels.h rename to libavutil/hwcontext_mediacodec.h index 57b650d27..101a9806d 100644 --- a/libavfilter/opencl_allkernels.h +++ b/libavutil/hwcontext_mediacodec.h @@ -1,6 +1,4 @@ /* - * Copyright (C) 2013 Wei Gao - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -18,12 +16,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_OPENCL_ALLKERNELS_H -#define AVFILTER_OPENCL_ALLKERNELS_H +#ifndef AVUTIL_HWCONTEXT_MEDIACODEC_H +#define AVUTIL_HWCONTEXT_MEDIACODEC_H -#include "avfilter.h" -#include "config.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; -void ff_opencl_register_filter_kernel_code_all(void); - -#endif /* AVFILTER_OPENCL_ALLKERNELS_H */ +#endif /* AVUTIL_HWCONTEXT_MEDIACODEC_H */ diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c new file mode 100644 index 000000000..a725a491e --- /dev/null +++ b/libavutil/hwcontext_opencl.c @@ -0,0 +1,2944 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "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_VAAPI_INTEL_MEDIA +#include +#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_VAAPI_BEIGNET + int vaapi_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 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; + + 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 = opencl_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_VAAPI_BEIGNET + { + int fail = 0; + + CL_FUNC(clCreateImageFromFdINTEL, + "Intel DRM to OpenCL image mapping"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "VAAPI to OpenCL mapping " + "not usable.\n"); + priv->vaapi_mapping_usable = 0; + } else { + priv->vaapi_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; + int err; + + 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_VAAPI_BEIGNET + 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; + } + + if (err < 0) + return err; + + return opencl_device_init(hwdev); +} + +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); + order = order * 10 + c + 1; + depth = comp->depth; + 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(2, CL_R); + CHANNEL_ORDER(3, CL_R); + CHANNEL_ORDER(4, CL_R); + CHANNEL_ORDER(12, CL_RG); + CHANNEL_ORDER(23, CL_RG); + CHANNEL_ORDER(1234, CL_RGBA); + CHANNEL_ORDER(3214, CL_BGRA); + CHANNEL_ORDER(4123, CL_ARGB); +#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 + + cle = clReleaseCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release frame " + "command queue: %d.\n", cle); + } +} + +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_VAAPI_BEIGNET + +typedef struct VAAPItoOpenCLMapping { + VAImage va_image; + VABufferInfo va_buffer_info; + + AVOpenCLFrameDescriptor frame; +} VAAPItoOpenCLMapping; + +static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc, + HWMapDescriptor *hwmap) +{ + VAAPItoOpenCLMapping *mapping = hwmap->priv; + AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx; + VASurfaceID surface_id; + VAStatus vas; + cl_int cle; + int i; + + surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; + av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n", + surface_id); + + for (i = 0; i < mapping->frame.nb_planes; i++) { + cle = clReleaseMemObject(mapping->frame.planes[i]); + if (cle != CL_SUCCESS) { + av_log(src_fc, AV_LOG_ERROR, "Failed to release CL " + "buffer of plane %d of VA image %#x (derived " + "from surface %#x): %d.\n", i, + mapping->va_image.buf, surface_id, cle); + } + } + + vas = vaReleaseBufferHandle(src_dev->display, + mapping->va_image.buf); + if (vas != VA_STATUS_SUCCESS) { + av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer " + "handle of image %#x (derived from surface %#x): " + "%d (%s).\n", mapping->va_image.buf, surface_id, + vas, vaErrorStr(vas)); + } + + vas = vaDestroyImage(src_dev->display, + mapping->va_image.image_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image " + "derived from surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + } + + av_free(mapping); +} + +static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx; + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + VAAPItoOpenCLMapping *mapping = NULL; + VASurfaceID surface_id; + VAStatus vas; + cl_int cle; + int err, p; + + surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n", + surface_id); + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + vas = vaDeriveImage(src_dev->display, surface_id, + &mapping->va_image); + if (vas != VA_STATUS_SUCCESS) { + av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from " + "surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + mapping->va_buffer_info.mem_type = + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + + vas = vaAcquireBufferHandle(src_dev->display, + mapping->va_image.buf, + &mapping->va_buffer_info); + if (vas != VA_STATUS_SUCCESS) { + av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer " + "handle from image %#x (derived from surface %#x): " + "%d (%s).\n", mapping->va_image.buf, surface_id, + vas, vaErrorStr(vas)); + vaDestroyImage(src_dev->display, mapping->va_image.buf); + err = AVERROR(EIO); + goto fail_derived; + } + + av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n", + mapping->va_buffer_info.handle); + + mapping->frame.nb_planes = mapping->va_image.num_planes; + for (p = 0; p < mapping->frame.nb_planes; p++) { + cl_import_image_info_intel image_info = { + .fd = mapping->va_buffer_info.handle, + .size = mapping->va_buffer_info.mem_size, + .type = CL_MEM_OBJECT_IMAGE2D, + .offset = mapping->va_image.offsets[p], + .row_pitch = mapping->va_image.pitches[p], + }; + cl_image_desc image_desc; + + err = opencl_get_plane_format(src_fc->sw_format, p, + mapping->va_image.width, + mapping->va_image.height, + &image_info.fmt, + &image_desc); + if (err < 0) { + av_log(dst_fc, AV_LOG_ERROR, "VA %#x (derived from " + "surface %#x) has invalid parameters: %d.\n", + mapping->va_image.buf, surface_id, err); + goto fail_mapped; + } + image_info.width = image_desc.image_width; + image_info.height = image_desc.image_height; + + mapping->frame.planes[p] = + priv->clCreateImageFromFdINTEL(dst_dev->context, + &image_info, &cle); + if (!mapping->frame.planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image " + "from plane %d of VA image %#x (derived from " + "surface %#x): %d.\n", p, + mapping->va_image.buf, surface_id, cle); + err = AVERROR(EIO); + goto fail_mapped; + } + + dst->data[p] = (uint8_t*)mapping->frame.planes[p]; + } + + err = ff_hwframe_map_create(src->hw_frames_ctx, + dst, src, &opencl_unmap_from_vaapi, + mapping); + if (err < 0) + goto fail_mapped; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail_mapped: + for (p = 0; p < mapping->frame.nb_planes; p++) { + if (mapping->frame.planes[p]) + clReleaseMemObject(mapping->frame.planes[p]); + } + vaReleaseBufferHandle(src_dev->display, mapping->va_image.buf); +fail_derived: + vaDestroyImage(src_dev->display, mapping->va_image.image_id); +fail: + av_freep(&mapping); + return err; +} + +#endif + +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 (src->format == AV_PIX_FMT_QSV) { + mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3]; + va_surface = *(VASurfaceID*)mfx_surface->Data.MemId; + } else 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) +{ + OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv; + av_assert0(dst->format == AV_PIX_FMT_OPENCL); + switch (src->format) { +#if HAVE_OPENCL_VAAPI_BEIGNET + case AV_PIX_FMT_VAAPI: + if (priv->vaapi_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) +{ + OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + switch (src_fc->device_ctx->type) { +#if HAVE_OPENCL_VAAPI_BEIGNET + case AV_HWDEVICE_TYPE_VAAPI: + if (!priv->vaapi_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/libavutil/hwcontext_opencl.h b/libavutil/hwcontext_opencl.h new file mode 100644 index 000000000..ef54486c9 --- /dev/null +++ b/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/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index f1d16d8bf..9b6040ba9 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -989,7 +989,6 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, int flags) { AVQSVDeviceContext *hwctx = ctx->hwctx; - QSVDeviceContext *s = ctx->internal->priv; mfxVersion ver = { { 3, 1 } }; mfxHDL handle; @@ -1029,6 +1028,23 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, 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; + } + + 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: " diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c index cc961f12f..29698d1b2 100644 --- a/libavutil/hwcontext_vaapi.c +++ b/libavutil/hwcontext_vaapi.c @@ -101,7 +101,9 @@ static const struct { MAP(NV12, YUV420, NV12), MAP(YV12, YUV420, YUV420P), // With U/V planes swapped. MAP(IYUV, YUV420, YUV420P), - //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver. +#ifdef VA_FOURCC_I420 + MAP(I420, YUV420, YUV420P), +#endif #ifdef VA_FOURCC_YV16 MAP(YV16, YUV422, YUV422P), // With U/V planes swapped. #endif @@ -625,24 +627,31 @@ static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, enum AVPixelFormat **formats) { VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv; - enum AVPixelFormat *pix_fmts, preferred_format; - int i, k; + enum AVPixelFormat *pix_fmts; + int i, k, sw_format_available; - preferred_format = hwfc->sw_format; + 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); - pix_fmts[0] = preferred_format; - k = 1; + 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 == preferred_format) + if (ctx->formats[i].pix_fmt == hwfc->sw_format) continue; av_assert0(k < ctx->nb_formats); pix_fmts[k++] = ctx->formats[i].pix_fmt; } - av_assert0(k == ctx->nb_formats); pix_fmts[k] = AV_PIX_FMT_NONE; *formats = pix_fmts; @@ -1076,11 +1085,80 @@ static void vaapi_unmap_to_drm(AVHWFramesContext *dst_fc, static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags) { +#if VA_CHECK_VERSION(1, 1, 0) + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VASurfaceID surface_id; + VAStatus vas; + VADRMPRIMESurfaceDescriptor va_desc; + AVDRMFrameDescriptor *drm_desc = NULL; + int err, i, j; + + surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + + vas = vaExportSurfaceHandle(hwctx->display, surface_id, + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, + VA_EXPORT_SURFACE_READ_ONLY | + VA_EXPORT_SURFACE_SEPARATE_LAYERS, + &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, 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; +#else // Older versions without vaExportSurfaceHandle() are not supported - // in theory this is possible with a combination of vaDeriveImage() // and vaAcquireBufferHandle(), but it doesn't carry enough metadata // to actually use the result in a generic way. return AVERROR(ENOSYS); +#endif } #endif diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c index 500517880..5af4fc20a 100644 --- a/libavutil/imgutils.c +++ b/libavutil/imgutils.c @@ -242,9 +242,10 @@ typedef struct ImgUtils { } ImgUtils; static const AVClass imgutils_class = { - .class_name = "IMGUTILS", - .item_name = av_default_item_name, - .version = LIBAVUTIL_VERSION_INT, + .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), }; diff --git a/libavutil/internal.h b/libavutil/internal.h index a2d73e3cc..c77dfa7d3 100644 --- a/libavutil/internal.h +++ b/libavutil/internal.h @@ -43,6 +43,7 @@ #include "cpu.h" #include "dict.h" #include "macros.h" +#include "mem.h" #include "pixfmt.h" #include "version.h" @@ -62,10 +63,10 @@ #endif #endif -#if defined(_MSC_VER) && CONFIG_SHARED -# define av_export __declspec(dllimport) +#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avutil) +# define av_export_avutil __declspec(dllimport) #else -# define av_export +# define av_export_avutil #endif #if HAVE_PRAGMA_DEPRECATED @@ -76,8 +77,8 @@ # 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 ignored \"-Wdeprecated-declarations\"") -# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") +# 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 @@ -110,24 +111,30 @@ DECLARE_ALIGNED(a, t, la_##v) s o; \ t (*v) o = la_##v -#define LOCAL_ALIGNED(a, t, v, ...) E1(LOCAL_ALIGNED_A(a, t, v, __VA_ARGS__,,)) +#define LOCAL_ALIGNED(a, t, v, ...) LOCAL_ALIGNED_##a(t, v, __VA_ARGS__) -#if HAVE_LOCAL_ALIGNED_8 +#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, ...) LOCAL_ALIGNED(8, t, v, __VA_ARGS__) +# define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_A(8, t, v, __VA_ARGS__,,)) #endif -#if HAVE_LOCAL_ALIGNED_16 +#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, ...) LOCAL_ALIGNED(16, t, v, __VA_ARGS__) +# define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_A(16, t, v, __VA_ARGS__,,)) #endif -#if HAVE_LOCAL_ALIGNED_32 +#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, ...) LOCAL_ALIGNED(32, t, v, __VA_ARGS__) +# 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)\ diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h index d54d4b91d..0c0309b4a 100644 --- a/libavutil/intreadwrite.h +++ b/libavutil/intreadwrite.h @@ -215,7 +215,7 @@ typedef union { * by per-arch headers. */ -#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) +#if defined(__GNUC__) union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; @@ -224,11 +224,6 @@ 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(__DECC) - -# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) -# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) - #elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64)) && AV_HAVE_FAST_UNALIGNED # define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) diff --git a/libavutil/log.c b/libavutil/log.c index be806202f..bd47f2a25 100644 --- a/libavutil/log.c +++ b/libavutil/log.c @@ -39,11 +39,9 @@ #include "common.h" #include "internal.h" #include "log.h" +#include "thread.h" -#if HAVE_PTHREADS -#include -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#endif +static AVMutex mutex = AV_MUTEX_INITIALIZER; #define LINE_SZ 1024 @@ -57,7 +55,7 @@ static int av_log_level = AV_LOG_INFO; static int flags; #define NB_LEVELS 8 -#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE #include static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = { [AV_LOG_PANIC /8] = 12, @@ -124,7 +122,7 @@ static int use_color = -1; static void check_color_terminal(void) { -#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE +#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") && @@ -159,7 +157,7 @@ static void colored_fputs(int level, int tint, const char *str) if (level == AV_LOG_INFO/8) local_use_color = 0; else local_use_color = use_color; -#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE if (local_use_color) SetConsoleTextAttribute(con, background | color[level]); fputs(str, stderr); @@ -317,9 +315,7 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) if (level > av_log_level) return; -#if HAVE_PTHREADS - pthread_mutex_lock(&mutex); -#endif + 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); @@ -356,9 +352,7 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) #endif end: av_bprint_finalize(part+3, NULL); -#if HAVE_PTHREADS - pthread_mutex_unlock(&mutex); -#endif + ff_mutex_unlock(&mutex); } static void (*av_log_callback)(void*, int, const char*, va_list) = diff --git a/libavutil/log.h b/libavutil/log.h index f0a57385d..d9554e609 100644 --- a/libavutil/log.h +++ b/libavutil/log.h @@ -334,20 +334,6 @@ void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, char *line, int line_size, int *print_prefix); -#if FF_API_DLOG -/** - * av_dlog macros - * @deprecated unused - * Useful to print debug messages that shouldn't get compiled in normally. - */ - -#ifdef DEBUG -# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) -#else -# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) -#endif -#endif /* FF_API_DLOG */ - /** * 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 diff --git a/libavutil/mastering_display_metadata.h b/libavutil/mastering_display_metadata.h index 847b0b62c..c23b07c3c 100644 --- a/libavutil/mastering_display_metadata.h +++ b/libavutil/mastering_display_metadata.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016 Neil Birkbeck * * This file is part of FFmpeg. diff --git a/libavutil/mem.c b/libavutil/mem.c index 36740f115..6149755a6 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c @@ -61,7 +61,7 @@ void free(void *ptr); #include "mem_internal.h" -#define ALIGN (HAVE_AVX ? 32 : 16) +#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 @@ -181,6 +181,20 @@ int av_reallocp(void *ptr, size_t size) 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) @@ -449,10 +463,15 @@ void av_memcpy_backptr(uint8_t *dst, int back, int cnt) void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) { - if (min_size < *size) + if (min_size <= *size) return ptr; - min_size = FFMAX(min_size + min_size / 16 + 32, min_size); + 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 diff --git a/libavutil/mem.h b/libavutil/mem.h index 527cd0319..7e0b12a8a 100644 --- a/libavutil/mem.h +++ b/libavutil/mem.h @@ -73,6 +73,19 @@ * @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 @@ -89,25 +102,23 @@ #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(__TI_COMPILER_VERSION__) - #define DECLARE_ALIGNED(n,t,v) \ - AV_PRAGMA(DATA_ALIGN(v,n)) \ - t __attribute__((aligned(n))) v - #define DECLARE_ASM_CONST(n,t,v) \ - AV_PRAGMA(DATA_ALIGN(v,n)) \ - static 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 @@ -206,12 +217,7 @@ void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); * be allocated * @see av_malloc() */ -av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t size) -{ - if (!size || nmemb >= INT_MAX / size) - return NULL; - return av_malloc(nmemb * size); -} +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(). @@ -226,12 +232,7 @@ av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t siz * @see av_mallocz() * @see av_malloc_array() */ -av_alloc_size(1, 2) static inline void *av_mallocz_array(size_t nmemb, size_t size) -{ - if (!size || nmemb >= INT_MAX / size) - return NULL; - return av_mallocz(nmemb * size); -} +av_alloc_size(1, 2) void *av_mallocz_array(size_t nmemb, size_t size); /** * Non-inlined equivalent of av_mallocz_array(). diff --git a/libavutil/mips/generic_macros_msa.h b/libavutil/mips/generic_macros_msa.h index c892529f0..6a4670466 100644 --- a/libavutil/mips/generic_macros_msa.h +++ b/libavutil/mips/generic_macros_msa.h @@ -1088,6 +1088,25 @@ out_m; \ } ) +#define CLIP_SW_0_255_MAX_SATU(in) \ +( { \ + v4i32 out_m; \ + \ + out_m = __msa_maxi_s_w((v4i32) in, 0); \ + out_m = (v4i32) __msa_sat_u_w((v4u32) out_m, 7); \ + out_m; \ +} ) +#define CLIP_SW2_0_255_MAX_SATU(in0, in1) \ +{ \ + in0 = CLIP_SW_0_255_MAX_SATU(in0); \ + in1 = CLIP_SW_0_255_MAX_SATU(in1); \ +} +#define CLIP_SW4_0_255_MAX_SATU(in0, in1, in2, in3) \ +{ \ + CLIP_SW2_0_255_MAX_SATU(in0, in1); \ + CLIP_SW2_0_255_MAX_SATU(in2, in3); \ +} + /* Description : Addition of 4 signed word elements 4 signed word elements of input vector are added together and resulted integer sum is returned @@ -2244,6 +2263,22 @@ out3 = in6 - in7; \ } +/* Description : Sign extend byte elements from right half of the vector + Arguments : Input - in (byte vector) + Output - out (sign extended halfword vector) + Return Type - signed halfword + Details : Sign bit of byte elements from input vector 'in' is + extracted and interleaved with same vector 'in' to generate + 8 halfword elements keeping sign intact +*/ +#define UNPCK_R_SB_SH(in, out) \ +{ \ + v16i8 sign_m; \ + \ + sign_m = __msa_clti_s_b((v16i8) in, 0); \ + out = (v8i16) __msa_ilvr_b(sign_m, (v16i8) in); \ +} + /* Description : Sign extend halfword elements from right half of the vector Arguments : Inputs - in (input halfword vector) Outputs - out (sign extended word vectors) diff --git a/libavutil/murmur3.c b/libavutil/murmur3.c index 4271e0145..ef853f404 100644 --- a/libavutil/murmur3.c +++ b/libavutil/murmur3.c @@ -60,7 +60,7 @@ static uint64_t inline get_k1(const uint8_t *src) return k; } -static uint64_t inline get_k2(const uint8_t *src) +static inline uint64_t get_k2(const uint8_t *src) { uint64_t k = AV_RL64(src + 8); k *= c2; @@ -69,7 +69,7 @@ static uint64_t inline get_k2(const uint8_t *src) return k; } -static uint64_t inline update_h1(uint64_t k, uint64_t h1, uint64_t h2) +static inline uint64_t update_h1(uint64_t k, uint64_t h1, uint64_t h2) { k ^= h1; k = ROT(k, 27); @@ -79,7 +79,7 @@ static uint64_t inline update_h1(uint64_t k, uint64_t h1, uint64_t h2) return k; } -static uint64_t inline update_h2(uint64_t k, uint64_t h1, uint64_t h2) +static inline uint64_t update_h2(uint64_t k, uint64_t h1, uint64_t h2) { k ^= h2; k = ROT(k, 31); diff --git a/libavutil/opencl.c b/libavutil/opencl.c deleted file mode 100644 index 202756516..000000000 --- a/libavutil/opencl.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "opencl.h" -#include "avstring.h" -#include "log.h" -#include "avassert.h" -#include "opt.h" - -#if HAVE_THREADS -#include "thread.h" -#include "atomic.h" - -static pthread_mutex_t * volatile atomic_opencl_lock = NULL; -#define LOCK_OPENCL pthread_mutex_lock(atomic_opencl_lock) -#define UNLOCK_OPENCL pthread_mutex_unlock(atomic_opencl_lock) -#else -#define LOCK_OPENCL -#define UNLOCK_OPENCL -#endif - -#define MAX_KERNEL_CODE_NUM 200 - -typedef struct { - int is_compiled; - const char *kernel_string; -} KernelCode; - -typedef struct { - const AVClass *class; - int log_offset; - void *log_ctx; - int init_count; - int opt_init_flag; - /** - * if set to 1, the OpenCL environment was created by the user and - * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper. - */ - int is_user_created; - int platform_idx; - int device_idx; - cl_platform_id platform_id; - cl_device_type device_type; - cl_context context; - cl_device_id device_id; - cl_command_queue command_queue; - int kernel_code_count; - KernelCode kernel_code[MAX_KERNEL_CODE_NUM]; - AVOpenCLDeviceList device_list; -} OpenclContext; - -#define OFFSET(x) offsetof(OpenclContext, x) - -static const AVOption opencl_options[] = { - { "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX}, - { "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX}, - { NULL } -}; - -static const AVClass openclutils_class = { - .class_name = "opencl", - .option = opencl_options, - .item_name = av_default_item_name, - .version = LIBAVUTIL_VERSION_INT, - .log_level_offset_offset = offsetof(OpenclContext, log_offset), - .parent_log_context_offset = offsetof(OpenclContext, log_ctx), -}; - -static OpenclContext opencl_ctx = {&openclutils_class}; - -static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU}; - -typedef struct { - int err_code; - const char *err_str; -} OpenclErrorMsg; - -static const OpenclErrorMsg opencl_err_msg[] = { - {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"}, - {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"}, - {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"}, - {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"}, - {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"}, - {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"}, - {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"}, - {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"}, - {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"}, - {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"}, - {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"}, - {CL_MAP_FAILURE, "MAP FAILURE"}, - {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"}, - {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"}, - {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"}, - {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"}, - {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"}, - {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"}, - {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"}, - {CL_INVALID_VALUE, "INVALID VALUE"}, - {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"}, - {CL_INVALID_PLATFORM, "INVALID PLATFORM"}, - {CL_INVALID_DEVICE, "INVALID DEVICE"}, - {CL_INVALID_CONTEXT, "INVALID CONTEXT"}, - {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"}, - {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"}, - {CL_INVALID_HOST_PTR, "INVALID HOST PTR"}, - {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"}, - {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"}, - {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"}, - {CL_INVALID_SAMPLER, "INVALID SAMPLER"}, - {CL_INVALID_BINARY, "INVALID BINARY"}, - {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"}, - {CL_INVALID_PROGRAM, "INVALID PROGRAM"}, - {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"}, - {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"}, - {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"}, - {CL_INVALID_KERNEL, "INVALID KERNEL"}, - {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"}, - {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"}, - {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"}, - {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"}, - {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"}, - {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"}, - {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"}, - {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"}, - {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"}, - {CL_INVALID_EVENT, "INVALID EVENT"}, - {CL_INVALID_OPERATION, "INVALID OPERATION"}, - {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"}, - {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"}, - {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"}, - {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"}, - {CL_INVALID_PROPERTY, "INVALID PROPERTY"}, - {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"}, - {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"}, - {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"}, - {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"}, -}; - -const char *av_opencl_errstr(cl_int status) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(opencl_err_msg); i++) { - if (opencl_err_msg[i].err_code == status) - return opencl_err_msg[i].err_str; - } - return "unknown error"; -} - -static void free_device_list(AVOpenCLDeviceList *device_list) -{ - int i, j; - if (!device_list || !device_list->platform_node) - return; - for (i = 0; i < device_list->platform_num; i++) { - if (!device_list->platform_node[i]) - continue; - for (j = 0; j < device_list->platform_node[i]->device_num; j++) { - av_freep(&(device_list->platform_node[i]->device_node[j]->device_name)); - av_freep(&(device_list->platform_node[i]->device_node[j])); - } - av_freep(&device_list->platform_node[i]->device_node); - av_freep(&(device_list->platform_node[i]->platform_name)); - av_freep(&device_list->platform_node[i]); - } - av_freep(&device_list->platform_node); - device_list->platform_num = 0; -} - -static int get_device_list(AVOpenCLDeviceList *device_list) -{ - cl_int status; - int i, j, k, device_num, total_devices_num, ret = 0; - int *devices_num; - cl_platform_id *platform_ids = NULL; - cl_device_id *device_ids = NULL; - AVOpenCLDeviceNode *device_node = NULL; - size_t platform_name_size = 0; - size_t device_name_size = 0; - status = clGetPlatformIDs(0, NULL, &device_list->platform_num); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - platform_ids = av_mallocz_array(device_list->platform_num, sizeof(cl_platform_id)); - if (!platform_ids) - return AVERROR(ENOMEM); - status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status)); - ret = AVERROR_EXTERNAL; - goto end; - } - device_list->platform_node = av_mallocz_array(device_list->platform_num, sizeof(AVOpenCLPlatformNode *)); - if (!device_list->platform_node) { - ret = AVERROR(ENOMEM); - goto end; - } - devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type)); - if (!devices_num) { - ret = AVERROR(ENOMEM); - goto end; - } - for (i = 0; i < device_list->platform_num; i++) { - device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode)); - if (!device_list->platform_node[i]) { - ret = AVERROR(ENOMEM); - goto end; - } - device_list->platform_node[i]->platform_id = platform_ids[i]; - status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR, - 0, NULL, &platform_name_size); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get size of platform name: %s\n", av_opencl_errstr(status)); - } else { - device_list->platform_node[i]->platform_name = av_malloc(platform_name_size * sizeof(char)); - if (!device_list->platform_node[i]->platform_name) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not allocate memory for device name: %s\n", av_opencl_errstr(status)); - } else { - status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR, - platform_name_size * sizeof(char), - device_list->platform_node[i]->platform_name, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get platform name: %s\n", av_opencl_errstr(status)); - } - } - } - total_devices_num = 0; - for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { - status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, - device_type[j], 0, NULL, &devices_num[j]); - total_devices_num += devices_num[j]; - } - device_list->platform_node[i]->device_node = av_mallocz_array(total_devices_num, sizeof(AVOpenCLDeviceNode *)); - if (!device_list->platform_node[i]->device_node) { - ret = AVERROR(ENOMEM); - goto end; - } - for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { - if (devices_num[j]) { - device_ids = av_mallocz_array(devices_num[j], sizeof(cl_device_id)); - if (!device_ids) { - ret = AVERROR(ENOMEM); - goto end; - } - status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j], - devices_num[j], device_ids, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get device ID: %s:\n", av_opencl_errstr(status)); - av_freep(&device_ids); - continue; - } - for (k = 0; k < devices_num[j]; k++) { - device_num = device_list->platform_node[i]->device_num; - device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode)); - if (!device_list->platform_node[i]->device_node[device_num]) { - ret = AVERROR(ENOMEM); - goto end; - } - device_node = device_list->platform_node[i]->device_node[device_num]; - device_node->device_id = device_ids[k]; - device_node->device_type = device_type[j]; - status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME, - 0, NULL, &device_name_size); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get size of device name: %s\n", av_opencl_errstr(status)); - continue; - } - device_node->device_name = av_malloc(device_name_size * sizeof(char)); - if (!device_node->device_name) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not allocate memory for device name: %s\n", av_opencl_errstr(status)); - continue; - } - status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME, - device_name_size * sizeof(char), - device_node->device_name, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get device name: %s\n", av_opencl_errstr(status)); - continue; - } - device_list->platform_node[i]->device_num++; - } - av_freep(&device_ids); - } - } - } -end: - av_freep(&platform_ids); - av_freep(&devices_num); - av_freep(&device_ids); - if (ret < 0) - free_device_list(device_list); - return ret; -} - -int av_opencl_get_device_list(AVOpenCLDeviceList **device_list) -{ - int ret = 0; - *device_list = av_mallocz(sizeof(AVOpenCLDeviceList)); - if (!(*device_list)) { - av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n"); - return AVERROR(ENOMEM); - } - ret = get_device_list(*device_list); - if (ret < 0) { - av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n"); - free_device_list(*device_list); - av_freep(device_list); - return ret; - } - return ret; -} - -void av_opencl_free_device_list(AVOpenCLDeviceList **device_list) -{ - free_device_list(*device_list); - av_freep(device_list); -} - -static inline int init_opencl_mtx(void) -{ -#if HAVE_THREADS - if (!atomic_opencl_lock) { - int err; - pthread_mutex_t *tmp = av_malloc(sizeof(pthread_mutex_t)); - if (!tmp) - return AVERROR(ENOMEM); - if ((err = pthread_mutex_init(tmp, NULL))) { - av_free(tmp); - return AVERROR(err); - } - if (avpriv_atomic_ptr_cas((void * volatile *)&atomic_opencl_lock, NULL, tmp)) { - pthread_mutex_destroy(tmp); - av_free(tmp); - } - } -#endif - return 0; -} - -int av_opencl_set_option(const char *key, const char *val) -{ - int ret = init_opencl_mtx( ); - if (ret < 0) - return ret; - LOCK_OPENCL; - if (!opencl_ctx.opt_init_flag) { - av_opt_set_defaults(&opencl_ctx); - opencl_ctx.opt_init_flag = 1; - } - ret = av_opt_set(&opencl_ctx, key, val, 0); - UNLOCK_OPENCL; - return ret; -} - -int av_opencl_get_option(const char *key, uint8_t **out_val) -{ - int ret = 0; - LOCK_OPENCL; - ret = av_opt_get(&opencl_ctx, key, 0, out_val); - UNLOCK_OPENCL; - return ret; -} - -void av_opencl_free_option(void) -{ - /*FIXME: free openclutils context*/ - LOCK_OPENCL; - av_opt_free(&opencl_ctx); - UNLOCK_OPENCL; -} - -AVOpenCLExternalEnv *av_opencl_alloc_external_env(void) -{ - AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv)); - if (!ext) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not malloc external opencl environment data space\n"); - } - return ext; -} - -void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env) -{ - av_freep(ext_opencl_env); -} - -int av_opencl_register_kernel_code(const char *kernel_code) -{ - int i, ret = init_opencl_mtx( ); - if (ret < 0) - return ret; - LOCK_OPENCL; - if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not register kernel code, maximum number of registered kernel code %d already reached\n", - MAX_KERNEL_CODE_NUM); - ret = AVERROR(EINVAL); - goto end; - } - for (i = 0; i < opencl_ctx.kernel_code_count; i++) { - if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) { - av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n"); - goto end; - } - } - opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code; - opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0; - opencl_ctx.kernel_code_count++; -end: - UNLOCK_OPENCL; - return ret; -} - -cl_program av_opencl_compile(const char *program_name, const char *build_opts) -{ - int i; - cl_int status, build_status; - int kernel_code_idx = 0; - const char *kernel_source = NULL; - size_t kernel_code_len; - char* ptr = NULL; - cl_program program = NULL; - size_t log_size; - char *log = NULL; - - LOCK_OPENCL; - for (i = 0; i < opencl_ctx.kernel_code_count; i++) { - // identify a program using a unique name within the kernel source - ptr = av_stristr(opencl_ctx.kernel_code[i].kernel_string, program_name); - if (ptr && !opencl_ctx.kernel_code[i].is_compiled) { - kernel_source = opencl_ctx.kernel_code[i].kernel_string; - kernel_code_len = strlen(opencl_ctx.kernel_code[i].kernel_string); - kernel_code_idx = i; - break; - } - } - if (!kernel_source) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Unable to find OpenCL kernel source '%s'\n", program_name); - goto end; - } - - /* create a CL program from kernel source */ - program = clCreateProgramWithSource(opencl_ctx.context, 1, &kernel_source, &kernel_code_len, &status); - if(status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Unable to create OpenCL program '%s': %s\n", program_name, av_opencl_errstr(status)); - program = NULL; - goto end; - } - - build_status = clBuildProgram(program, 1, &(opencl_ctx.device_id), build_opts, NULL, NULL); - status = clGetProgramBuildInfo(program, opencl_ctx.device_id, - CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Failed to get compilation log: %s\n", - av_opencl_errstr(status)); - } else { - log = av_malloc(log_size); - if (log) { - status = clGetProgramBuildInfo(program, opencl_ctx.device_id, - CL_PROGRAM_BUILD_LOG, log_size, - log, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Failed to get compilation log: %s\n", - av_opencl_errstr(status)); - } else { - int level = build_status == CL_SUCCESS ? AV_LOG_DEBUG : - AV_LOG_ERROR; - av_log(&opencl_ctx, level, "Compilation log:\n%s\n", log); - } - } - av_freep(&log); - } - if (build_status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Compilation failed with OpenCL program '%s': %s\n", - program_name, av_opencl_errstr(build_status)); - program = NULL; - goto end; - } - - opencl_ctx.kernel_code[kernel_code_idx].is_compiled = 1; -end: - UNLOCK_OPENCL; - return program; -} - -cl_command_queue av_opencl_get_command_queue(void) -{ - return opencl_ctx.command_queue; -} - -static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env) -{ - cl_int status; - cl_context_properties cps[3]; - int i, ret = 0; - AVOpenCLDeviceNode *device_node = NULL; - - if (ext_opencl_env) { - if (opencl_ctx->is_user_created) - return 0; - opencl_ctx->platform_id = ext_opencl_env->platform_id; - opencl_ctx->is_user_created = 1; - opencl_ctx->command_queue = ext_opencl_env->command_queue; - opencl_ctx->context = ext_opencl_env->context; - opencl_ctx->device_id = ext_opencl_env->device_id; - opencl_ctx->device_type = ext_opencl_env->device_type; - } else { - if (!opencl_ctx->is_user_created) { - if (!opencl_ctx->device_list.platform_num) { - ret = get_device_list(&opencl_ctx->device_list); - if (ret < 0) { - return ret; - } - } - if (opencl_ctx->platform_idx >= 0) { - if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) { - av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n"); - return AVERROR(EINVAL); - } - if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) { - av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n", - opencl_ctx->platform_idx); - return AVERROR(EINVAL); - } - opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id; - } else { - /* get a usable platform by default*/ - for (i = 0; i < opencl_ctx->device_list.platform_num; i++) { - if (opencl_ctx->device_list.platform_node[i]->device_num) { - opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id; - opencl_ctx->platform_idx = i; - break; - } - } - } - if (!opencl_ctx->platform_id) { - av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n"); - return AVERROR_EXTERNAL; - } - /* get a usable device*/ - if (opencl_ctx->device_idx >= 0) { - if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) { - av_log(opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx); - return AVERROR(EINVAL); - } - } else { - opencl_ctx->device_idx = 0; - } - - device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx]; - opencl_ctx->device_id = device_node->device_id; - opencl_ctx->device_type = device_node->device_type; - - /* - * Use available platform. - */ - av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, Device Name: %s\n", - opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name, - device_node->device_name); - cps[0] = CL_CONTEXT_PLATFORM; - cps[1] = (cl_context_properties)opencl_ctx->platform_id; - cps[2] = 0; - - opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type, - NULL, NULL, &status); - if (status != CL_SUCCESS) { - av_log(opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL context from device type: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id, - 0, &status); - if (status != CL_SUCCESS) { - av_log(opencl_ctx, AV_LOG_ERROR, - "Could not create OpenCL command queue: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - } - } - return ret; -} - -int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env) -{ - int ret = init_opencl_mtx( ); - if (ret < 0) - return ret; - LOCK_OPENCL; - if (!opencl_ctx.init_count) { - if (!opencl_ctx.opt_init_flag) { - av_opt_set_defaults(&opencl_ctx); - opencl_ctx.opt_init_flag = 1; - } - ret = init_opencl_env(&opencl_ctx, ext_opencl_env); - if (ret < 0) - goto end; - if (opencl_ctx.kernel_code_count <= 0) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "No kernel code is registered, compile kernel file failed\n"); - ret = AVERROR(EINVAL); - goto end; - } - } - opencl_ctx.init_count++; -end: - UNLOCK_OPENCL; - return ret; -} - -void av_opencl_uninit(void) -{ - int i; - cl_int status; - LOCK_OPENCL; - opencl_ctx.init_count--; - if (opencl_ctx.is_user_created) - goto end; - if (opencl_ctx.init_count > 0) - goto end; - if (opencl_ctx.command_queue) { - status = clReleaseCommandQueue(opencl_ctx.command_queue); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not release OpenCL command queue: %s\n", av_opencl_errstr(status)); - } - opencl_ctx.command_queue = NULL; - } - if (opencl_ctx.context) { - status = clReleaseContext(opencl_ctx.context); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not release OpenCL context: %s\n", av_opencl_errstr(status)); - } - opencl_ctx.context = NULL; - } - for (i = 0; i < opencl_ctx.kernel_code_count; i++) { - opencl_ctx.kernel_code[i].is_compiled = 0; - } - free_device_list(&opencl_ctx.device_list); -end: - if (opencl_ctx.init_count <= 0) - av_opt_free(&opencl_ctx); //FIXME: free openclutils context - UNLOCK_OPENCL; -} - -int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr) -{ - cl_int status; - *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -void av_opencl_buffer_release(cl_mem *cl_buf) -{ - cl_int status = 0; - if (!cl_buf) - return; - status = clReleaseMemObject(*cl_buf); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not release OpenCL buffer: %s\n", av_opencl_errstr(status)); - } - memset(cl_buf, 0, sizeof(*cl_buf)); -} - -int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size) -{ - cl_int status; - void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf, - CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size, - 0, NULL, NULL, &status); - - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - memcpy(mapped, src_buf, buf_size); - - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size) -{ - cl_int status; - void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf, - CL_TRUE, CL_MAP_READ, 0, buf_size, - 0, NULL, NULL, &status); - - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - memcpy(dst_buf, mapped, buf_size); - - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset, - uint8_t **src_data, int *plane_size, int plane_num) -{ - int i, buffer_size = 0; - uint8_t *temp; - cl_int status; - void *mapped; - if ((unsigned int)plane_num > 8) { - return AVERROR(EINVAL); - } - for (i = 0;i < plane_num;i++) { - buffer_size += plane_size[i]; - } - if (buffer_size > cl_buffer_size) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Cannot write image to OpenCL buffer: buffer too small\n"); - return AVERROR(EINVAL); - } - mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf, - CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset, - 0, NULL, NULL, &status); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - temp = mapped; - temp += dst_cl_offset; - for (i = 0; i < plane_num; i++) { - memcpy(temp, src_data[i], plane_size[i]); - temp += plane_size[i]; - } - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num, - cl_mem src_cl_buf, size_t cl_buffer_size) -{ - int i,buffer_size = 0,ret = 0; - uint8_t *temp; - void *mapped; - cl_int status; - if ((unsigned int)plane_num > 8) { - return AVERROR(EINVAL); - } - for (i = 0; i < plane_num; i++) { - buffer_size += plane_size[i]; - } - if (buffer_size > cl_buffer_size) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Cannot write image to CPU buffer: OpenCL buffer too small\n"); - return AVERROR(EINVAL); - } - mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf, - CL_TRUE, CL_MAP_READ, 0, buffer_size, - 0, NULL, NULL, &status); - - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - temp = mapped; - if (ret >= 0) { - for (i = 0; i < plane_num; i++) { - memcpy(dst_data[i], temp, plane_size[i]); - temp += plane_size[i]; - } - } - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device_node, cl_platform_id platform, - int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env)) -{ - int64_t ret = 0; - cl_int status; - cl_context_properties cps[3]; - AVOpenCLExternalEnv *ext_opencl_env = NULL; - - ext_opencl_env = av_opencl_alloc_external_env(); - ext_opencl_env->device_id = device_node->device_id; - ext_opencl_env->device_type = device_node->device_type; - av_log(&opencl_ctx, AV_LOG_VERBOSE, "Performing test on OpenCL device %s\n", - device_node->device_name); - - cps[0] = CL_CONTEXT_PLATFORM; - cps[1] = (cl_context_properties)platform; - cps[2] = 0; - ext_opencl_env->context = clCreateContextFromType(cps, ext_opencl_env->device_type, - NULL, NULL, &status); - if (status != CL_SUCCESS || !ext_opencl_env->context) { - ret = AVERROR_EXTERNAL; - goto end; - } - ext_opencl_env->command_queue = clCreateCommandQueue(ext_opencl_env->context, - ext_opencl_env->device_id, 0, &status); - if (status != CL_SUCCESS || !ext_opencl_env->command_queue) { - ret = AVERROR_EXTERNAL; - goto end; - } - ret = benchmark(ext_opencl_env); - if (ret < 0) - av_log(&opencl_ctx, AV_LOG_ERROR, "Benchmark failed with OpenCL device %s\n", - device_node->device_name); -end: - if (ext_opencl_env->command_queue) - clReleaseCommandQueue(ext_opencl_env->command_queue); - if (ext_opencl_env->context) - clReleaseContext(ext_opencl_env->context); - av_opencl_free_external_env(&ext_opencl_env); - return ret; -} diff --git a/libavutil/opencl.h b/libavutil/opencl.h deleted file mode 100644 index b709927c4..000000000 --- a/libavutil/opencl.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - * OpenCL wrapper - * - * This interface is considered still experimental and its API and ABI may - * change without prior notice. - */ - -#ifndef AVUTIL_OPENCL_H -#define AVUTIL_OPENCL_H - -#define CL_USE_DEPRECATED_OPENCL_1_2_APIS 1 -#ifdef __APPLE__ -#include -#else -#include -#endif -#include -#include "dict.h" - -#include "libavutil/version.h" - -#define AV_OPENCL_KERNEL( ... )# __VA_ARGS__ - -typedef struct { - int device_type; - char *device_name; - cl_device_id device_id; -} AVOpenCLDeviceNode; - -typedef struct { - cl_platform_id platform_id; - char *platform_name; - int device_num; - AVOpenCLDeviceNode **device_node; -} AVOpenCLPlatformNode; - -typedef struct { - int platform_num; - AVOpenCLPlatformNode **platform_node; -} AVOpenCLDeviceList; - -typedef struct { - cl_platform_id platform_id; - cl_device_type device_type; - cl_context context; - cl_device_id device_id; - cl_command_queue command_queue; - char *platform_name; -} AVOpenCLExternalEnv; - -/** - * Get OpenCL device list. - * - * It must be freed with av_opencl_free_device_list(). - * - * @param device_list pointer to OpenCL environment device list, - * should be released by av_opencl_free_device_list() - * - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_get_device_list(AVOpenCLDeviceList **device_list); - -/** - * Free OpenCL device list. - * - * @param device_list pointer to OpenCL environment device list - * created by av_opencl_get_device_list() - */ -void av_opencl_free_device_list(AVOpenCLDeviceList **device_list); - -/** - * Set option in the global OpenCL context. - * - * This options affect the operation performed by the next - * av_opencl_init() operation. - * - * The currently accepted options are: - * - platform: set index of platform in device list - * - device: set index of device in device list - * - * See reference "OpenCL Specification Version: 1.2 chapter 5.6.4". - * - * @param key option key - * @param val option value - * @return >=0 on success, a negative error code in case of failure - * @see av_opencl_get_option() - */ -int av_opencl_set_option(const char *key, const char *val); - -/** - * Get option value from the global OpenCL context. - * - * @param key option key - * @param out_val pointer to location where option value will be - * written, must be freed with av_freep() - * @return >=0 on success, a negative error code in case of failure - * @see av_opencl_set_option() - */ -int av_opencl_get_option(const char *key, uint8_t **out_val); - -/** - * Free option values of the global OpenCL context. - * - */ -void av_opencl_free_option(void); - -/** - * Allocate OpenCL external environment. - * - * It must be freed with av_opencl_free_external_env(). - * - * @return pointer to allocated OpenCL external environment - */ -AVOpenCLExternalEnv *av_opencl_alloc_external_env(void); - -/** - * Free OpenCL external environment. - * - * @param ext_opencl_env pointer to OpenCL external environment - * created by av_opencl_alloc_external_env() - */ -void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env); - -/** - * Get OpenCL error string. - * - * @param status OpenCL error code - * @return OpenCL error string - */ -const char *av_opencl_errstr(cl_int status); - -/** - * Register kernel code. - * - * The registered kernel code is stored in a global context, and compiled - * in the runtime environment when av_opencl_init() is called. - * - * @param kernel_code kernel code to be compiled in the OpenCL runtime environment - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_register_kernel_code(const char *kernel_code); - -/** - * Initialize the run time OpenCL environment - * - * @param ext_opencl_env external OpenCL environment, created by an - * application program, ignored if set to NULL - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env); - -/** - * compile specific OpenCL kernel source - * - * @param program_name pointer to a program name used for identification - * @param build_opts pointer to a string that describes the preprocessor - * build options to be used for building the program - * @return a cl_program object - */ -cl_program av_opencl_compile(const char *program_name, const char* build_opts); - -/** - * get OpenCL command queue - * - * @return a cl_command_queue object - */ -cl_command_queue av_opencl_get_command_queue(void); - -/** - * Create OpenCL buffer. - * - * The buffer is used to save the data used or created by an OpenCL - * kernel. - * The created buffer must be released with av_opencl_buffer_release(). - * - * See clCreateBuffer() function reference for more information about - * the parameters. - * - * @param cl_buf pointer to OpenCL buffer - * @param cl_buf_size size in bytes of the OpenCL buffer to create - * @param flags flags used to control buffer attributes - * @param host_ptr host pointer of the OpenCL buffer - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr); - -/** - * Write OpenCL buffer with data from src_buf. - * - * @param dst_cl_buf pointer to OpenCL destination buffer - * @param src_buf pointer to source buffer - * @param buf_size size in bytes of the source and destination buffers - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size); - -/** - * Read data from OpenCL buffer to memory buffer. - * - * @param dst_buf pointer to destination buffer (CPU memory) - * @param src_cl_buf pointer to source OpenCL buffer - * @param buf_size size in bytes of the source and destination buffers - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size); - -/** - * Write image data from memory to OpenCL buffer. - * - * The source must be an array of pointers to image plane buffers. - * - * @param dst_cl_buf pointer to destination OpenCL buffer - * @param dst_cl_buf_size size in bytes of OpenCL buffer - * @param dst_cl_buf_offset the offset of the OpenCL buffer start position - * @param src_data array of pointers to source plane buffers - * @param src_plane_sizes array of sizes in bytes of the source plane buffers - * @param src_plane_num number of source image planes - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset, - uint8_t **src_data, int *plane_size, int plane_num); - -/** - * Read image data from OpenCL buffer. - * - * @param dst_data array of pointers to destination plane buffers - * @param dst_plane_sizes array of pointers to destination plane buffers - * @param dst_plane_num number of destination image planes - * @param src_cl_buf pointer to source OpenCL buffer - * @param src_cl_buf_size size in bytes of OpenCL buffer - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num, - cl_mem src_cl_buf, size_t cl_buffer_size); - -/** - * Release OpenCL buffer. - * - * @param cl_buf pointer to OpenCL buffer to release, which was - * previously filled with av_opencl_buffer_create() - */ -void av_opencl_buffer_release(cl_mem *cl_buf); - -/** - * Release OpenCL environment. - * - * The OpenCL environment is effectively released only if all the created - * kernels had been released with av_opencl_release_kernel(). - */ -void av_opencl_uninit(void); - -/** - * Benchmark an OpenCL device with a user defined callback function. This function - * sets up an external OpenCL environment including context and command queue on - * the device then tears it down in the end. The callback function should perform - * the rest of the work. - * - * @param device pointer to the OpenCL device to be used - * @param platform cl_platform_id handle to which the device belongs to - * @param benchmark callback function to perform the benchmark, return a - * negative value in case of failure - * @return the score passed from the callback function, a negative error code in case - * of failure - */ -int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device, cl_platform_id platform, - int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env)); - -#endif /* AVUTIL_OPENCL_H */ diff --git a/libavutil/opencl_internal.c b/libavutil/opencl_internal.c deleted file mode 100644 index bdb41936f..000000000 --- a/libavutil/opencl_internal.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "opencl_internal.h" -#include "libavutil/log.h" - -int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...) -{ - int ret = 0; - va_list arg_ptr; - void *param; - size_t param_size; - cl_int status; - if (!opencl_param->kernel) { - av_log(opencl_param->ctx, AV_LOG_ERROR, "OpenCL kernel must be set\n"); - return AVERROR(EINVAL); - } - va_start(arg_ptr, opencl_param); - do { - param = va_arg(arg_ptr, void *); - if (!param) - break; - param_size = va_arg(arg_ptr, size_t); - if (!param_size) { - av_log(opencl_param->ctx, AV_LOG_ERROR, "Parameter size must not be 0\n"); - ret = AVERROR(EINVAL); - goto end; - } - status = clSetKernelArg(opencl_param->kernel, opencl_param->param_num, param_size, param); - if (status != CL_SUCCESS) { - av_log(opencl_param->ctx, AV_LOG_ERROR, "Cannot set kernel argument: %s\n", av_opencl_errstr(status)); - ret = AVERROR_EXTERNAL; - goto end; - } - opencl_param->param_num++; - } while (param && param_size); -end: - va_end(arg_ptr); - return ret; -} diff --git a/libavutil/opt.h b/libavutil/opt.h index 0d893795d..555929dd6 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -275,9 +275,6 @@ typedef struct AVOption { 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 -#if FF_API_OPT_TYPE_METADATA -#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... -#endif #define AV_OPT_FLAG_AUDIO_PARAM 8 #define AV_OPT_FLAG_VIDEO_PARAM 16 #define AV_OPT_FLAG_SUBTITLE_PARAM 32 diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index 2cfab89c0..e77d5f44b 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -326,22 +326,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR, }, -#if FF_API_XVMC - [AV_PIX_FMT_XVMC_MPEG2_MC] = { - .name = "xvmcmc", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_XVMC_MPEG2_IDCT] = { - .name = "xvmcidct", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, -#endif /* FF_API_XVMC */ -#if !FF_API_XVMC [AV_PIX_FMT_XVMC] = { .name = "xvmc", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, -#endif /* !FF_API_XVMC */ [AV_PIX_FMT_UYVY422] = { .name = "uyvy422", .nb_components = 3, @@ -989,44 +977,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, }, -#if FF_API_VDPAU - [AV_PIX_FMT_VDPAU_H264] = { - .name = "vdpau_h264", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_MPEG1] = { - .name = "vdpau_mpeg1", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_MPEG2] = { - .name = "vdpau_mpeg2", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_WMV3] = { - .name = "vdpau_wmv3", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_VC1] = { - .name = "vdpau_vc1", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_MPEG4] = { - .name = "vdpau_mpeg4", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, -#endif [AV_PIX_FMT_RGB48BE] = { .name = "rgb48be", .nb_components = 3, @@ -1670,12 +1620,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .log2_chroma_h = 1, .flags = AV_PIX_FMT_FLAG_HWACCEL, }, - [AV_PIX_FMT_VDA_VLD] = { - .name = "vda_vld", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, [AV_PIX_FMT_YA8] = { .name = "ya8", .nb_components = 2, @@ -2029,10 +1973,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, }, - [AV_PIX_FMT_VDA] = { - .name = "vda", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, [AV_PIX_FMT_QSV] = { .name = "qsv", .flags = AV_PIX_FMT_FLAG_HWACCEL, @@ -2241,6 +2181,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .name = "drm_prime", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, + [AV_PIX_FMT_OPENCL] = { + .name = "opencl", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, }; #if FF_API_PLUS1_MINUS1 FF_ENABLE_DEPRECATION_WARNINGS diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h index fc3737c4a..ea046033a 100644 --- a/libavutil/pixdesc.h +++ b/libavutil/pixdesc.h @@ -225,11 +225,6 @@ 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. * - * See av_get_chroma_sub_sample() for a function that asserts a - * valid pixel format instead of returning an error code. - * Its recommended that you use avcodec_get_chroma_sub_sample unless - * you do check the return code! - * * @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) diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index 24889c8e5..e184a5667 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -74,11 +74,6 @@ enum AVPixelFormat { 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 -#if FF_API_XVMC - AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing - AV_PIX_FMT_XVMC_MPEG2_IDCT, - AV_PIX_FMT_XVMC = AV_PIX_FMT_XVMC_MPEG2_IDCT, -#endif /* FF_API_XVMC */ 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) @@ -100,13 +95,6 @@ enum AVPixelFormat { 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) -#if FF_API_VDPAU - AV_PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers -#endif 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 @@ -142,9 +130,6 @@ enum AVPixelFormat { 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 -#if FF_API_VDPAU - AV_PIX_FMT_VDPAU_MPEG4, ///< MPEG-4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers -#endif 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 @@ -176,7 +161,6 @@ enum AVPixelFormat { 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_VDA_VLD, ///< hardware decoding through VDA 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 @@ -221,8 +205,6 @@ enum AVPixelFormat { AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb - AV_PIX_FMT_VDA, ///< HW acceleration through VDA, data[3] contains a CVPixelBufferRef - AV_PIX_FMT_YA16BE, ///< 16 bits gray, 16 bits alpha (big-endian) AV_PIX_FMT_YA16LE, ///< 16 bits gray, 16 bits alpha (little-endian) @@ -248,7 +230,7 @@ enum AVPixelFormat { */ AV_PIX_FMT_CUDA, - AV_PIX_FMT_0RGB=0x123+4,///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + 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 @@ -283,9 +265,9 @@ enum AVPixelFormat { 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 */ -#if !FF_API_XVMC + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing -#endif /* !FF_API_XVMC */ + 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 @@ -340,6 +322,13 @@ enum AVPixelFormat { * 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_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 }; diff --git a/libavutil/ppc/util_altivec.h b/libavutil/ppc/util_altivec.h index 6ab7e5083..2548011be 100644 --- a/libavutil/ppc/util_altivec.h +++ b/libavutil/ppc/util_altivec.h @@ -28,10 +28,6 @@ #include "config.h" -#if HAVE_ALTIVEC_H -#include -#endif - /*********************************************************************** * Vector types **********************************************************************/ @@ -56,6 +52,7 @@ #define zero_s32v (vec_s32) zerov #if HAVE_ALTIVEC +#include // used to build registers permutation vectors (vcprm) // the 's' are for words in the _s_econd vector diff --git a/libavutil/random_seed.c b/libavutil/random_seed.c index d1c9a3f70..881c23c8c 100644 --- a/libavutil/random_seed.c +++ b/libavutil/random_seed.c @@ -26,7 +26,7 @@ #if HAVE_IO_H #include #endif -#if HAVE_CRYPTGENRANDOM +#if HAVE_WINCRYPT #include #include #endif @@ -121,7 +121,7 @@ uint32_t av_get_random_seed(void) { uint32_t seed; -#if HAVE_CRYPTGENRANDOM +#if HAVE_WINCRYPT HCRYPTPROV provider; if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c index c43f87a2a..dfbe551ef 100644 --- a/libavutil/slicethread.c +++ b/libavutil/slicethread.c @@ -99,10 +99,6 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, AVSliceThread *ctx; int nb_workers, i; -#if HAVE_W32THREADS - w32thread_init(); -#endif - av_assert0(nb_threads >= 0); if (!nb_threads) { int nb_cpus = av_cpu_count(); diff --git a/libavutil/softfloat.h b/libavutil/softfloat.h index b13d728f3..a651406f7 100644 --- a/libavutil/softfloat.h +++ b/libavutil/softfloat.h @@ -43,6 +43,7 @@ static const SoftFloat FLOAT_EPSILON = { 0x29F16B12, -16}; 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}; /** diff --git a/libavutil/stereo3d.h b/libavutil/stereo3d.h index 54f4c4c5c..d421aac2a 100644 --- a/libavutil/stereo3d.h +++ b/libavutil/stereo3d.h @@ -141,6 +141,25 @@ enum AVStereo3DType { 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. @@ -164,6 +183,11 @@ typedef struct AVStereo3D { * Additional information about the frame packing. */ int flags; + + /** + * Determines which views are packed. + */ + enum AVStereo3DView view; } AVStereo3D; /** diff --git a/libavutil/tests/.gitignore b/libavutil/tests/.gitignore new file mode 100644 index 000000000..8ede07088 --- /dev/null +++ b/libavutil/tests/.gitignore @@ -0,0 +1,48 @@ +/adler32 +/aes +/aes_ctr +/atomic +/audio_fifo +/avstring +/base64 +/blowfish +/bprint +/camellia +/cast5 +/color_utils +/cpu +/cpu_init +/crc +/des +/dict +/display +/error +/eval +/fifo +/file +/hash +/hmac +/imgutils +/lfg +/lls +/log +/lzo +/md5 +/murmur3 +/opt +/parseutils +/pca +/pixdesc +/pixelutils +/pixfmt_best +/random_seed +/rational +/ripemd +/sha +/sha512 +/softfloat +/tea +/tree +/twofish +/utf8 +/xtea diff --git a/libavutil/tests/cpu.c b/libavutil/tests/cpu.c index f02a54cbb..ce45b715a 100644 --- a/libavutil/tests/cpu.c +++ b/libavutil/tests/cpu.c @@ -73,6 +73,7 @@ static const struct { { AV_CPU_FLAG_BMI1, "bmi1" }, { AV_CPU_FLAG_BMI2, "bmi2" }, { AV_CPU_FLAG_AESNI, "aesni" }, + { AV_CPU_FLAG_AVX512, "avx512" }, #endif { 0 } }; diff --git a/libavutil/tests/hmac.c b/libavutil/tests/hmac.c index 5eeb63ce0..0fa50e457 100644 --- a/libavutil/tests/hmac.c +++ b/libavutil/tests/hmac.c @@ -70,7 +70,7 @@ int main(void) } /* SHA-2 */ - for (i = AV_HMAC_SHA224; i <= AV_HMAC_SHA256; i++) { + for (i = AV_HMAC_SHA224; i <= AV_HMAC_SHA512; i++) { hmac = av_hmac_alloc(i); if (!hmac) return 1; @@ -83,17 +83,5 @@ int main(void) av_hmac_free(hmac); } - for (i = AV_HMAC_SHA384; i <= AV_HMAC_SHA512; i++) { - hmac = av_hmac_alloc(i); - if (!hmac) - return 1; - // RFC 4231 test vectors - test(hmac, key1, sizeof(key1), data1, sizeof(data1)); - test(hmac, key2, sizeof(key2), data2, sizeof(data2)); - test(hmac, key3, 20, data3, sizeof(data3)); - test(hmac, key3, sizeof(key3), data4, sizeof(data4)); - test(hmac, key3, sizeof(key3), data6, sizeof(data6)); - av_hmac_free(hmac); - } return 0; } diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c index 568eb4566..f4cfa590a 100644 --- a/libavutil/tests/opt.c +++ b/libavutil/tests/opt.c @@ -98,9 +98,9 @@ static const char *test_get_name(void *ctx) } static const AVClass test_class = { - "TestContext", - test_get_name, - test_options + .class_name = "TestContext", + .item_name = test_get_name, + .option = test_options, }; static void log_callback_help(void *ptr, int level, const char *fmt, va_list vl) diff --git a/libavutil/thread.h b/libavutil/thread.h index f108e2005..cc5272d37 100644 --- a/libavutil/thread.h +++ b/libavutil/thread.h @@ -134,6 +134,7 @@ static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_ #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 @@ -148,11 +149,12 @@ static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_ #else #define AVMutex char +#define AV_MUTEX_INITIALIZER 0 -#define ff_mutex_init(mutex, attr) (0) -#define ff_mutex_lock(mutex) (0) -#define ff_mutex_unlock(mutex) (0) -#define ff_mutex_destroy(mutex) (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 diff --git a/libavutil/timecode.c b/libavutil/timecode.c index c0c67c847..e9d8504ee 100644 --- a/libavutil/timecode.c +++ b/libavutil/timecode.c @@ -155,7 +155,7 @@ static int check_fps(int fps) static int check_timecode(void *log_ctx, AVTimecode *tc) { if ((int)tc->fps <= 0) { - av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate must be specified\n"); + 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) { diff --git a/libavutil/timer.h b/libavutil/timer.h index f7ab455df..0bb353cfc 100644 --- a/libavutil/timer.h +++ b/libavutil/timer.h @@ -42,7 +42,7 @@ #include #include -#if HAVE_MACH_MACH_TIME_H +#if HAVE_MACH_ABSOLUTE_TIME #include #endif diff --git a/libavutil/utils.c b/libavutil/utils.c index 2c170db2e..230081ea4 100644 --- a/libavutil/utils.c +++ b/libavutil/utils.c @@ -41,9 +41,6 @@ unsigned avutil_version(void) if (checks_done) return LIBAVUTIL_VERSION_INT; -#if FF_API_VDPAU - av_assert0(AV_PIX_FMT_VDA_VLD == 81); //check if the pix fmt enum has not had anything inserted or removed by mistake -#endif av_assert0(AV_SAMPLE_FMT_DBLP == 9); av_assert0(AVMEDIA_TYPE_ATTACHMENT == 4); av_assert0(AV_PICTURE_TYPE_BI == 7); diff --git a/libavutil/version.h b/libavutil/version.h index f594dc069..d81ec6fa7 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -78,9 +78,8 @@ * @{ */ - -#define LIBAVUTIL_VERSION_MAJOR 55 -#define LIBAVUTIL_VERSION_MINOR 78 +#define LIBAVUTIL_VERSION_MAJOR 56 +#define LIBAVUTIL_VERSION_MINOR 7 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -106,38 +105,26 @@ * @{ */ -#ifndef FF_API_VDPAU -#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_XVMC -#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_OPT_TYPE_METADATA -#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_DLOG -#define FF_API_DLOG (LIBAVUTIL_VERSION_MAJOR < 56) -#endif #ifndef FF_API_VAAPI -#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_FRAME_QP -#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_PLUS1_MINUS1 -#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_ERROR_FRAME -#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_CRC_BIG_TABLE -#define FF_API_CRC_BIG_TABLE (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_PKT_PTS -#define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 56) +#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 < 56) +#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 diff --git a/libavutil/wchar_filename.h b/libavutil/wchar_filename.h index 2ade321be..142d50e7c 100644 --- a/libavutil/wchar_filename.h +++ b/libavutil/wchar_filename.h @@ -19,7 +19,7 @@ #ifndef AVUTIL_WCHAR_FILENAME_H #define AVUTIL_WCHAR_FILENAME_H -#if defined(_WIN32) && !defined(__MINGW32CE__) +#ifdef _WIN32 #include #include "mem.h" diff --git a/libavutil/x86/cpu.c b/libavutil/x86/cpu.c index f33088c8c..aca893174 100644 --- a/libavutil/x86/cpu.c +++ b/libavutil/x86/cpu.c @@ -97,6 +97,7 @@ int ff_get_cpu_flags_x86(void) 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 */ @@ -132,8 +133,8 @@ int ff_get_cpu_flags_x86(void) /* Check OXSAVE and AVX bits */ if ((ecx & 0x18000000) == 0x18000000) { /* Check for OS support */ - xgetbv(0, eax, edx); - if ((eax & 0x6) == 0x6) { + xgetbv(0, xcr0_lo, xcr0_hi); + if ((xcr0_lo & 0x6) == 0x6) { rval |= AV_CPU_FLAG_AVX; if (ecx & 0x00001000) rval |= AV_CPU_FLAG_FMA3; @@ -147,6 +148,13 @@ int ff_get_cpu_flags_x86(void) #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) { @@ -238,6 +246,8 @@ 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 | diff --git a/libavutil/x86/cpu.h b/libavutil/x86/cpu.h index 309b8e746..7f4e5d08b 100644 --- a/libavutil/x86/cpu.h +++ b/libavutil/x86/cpu.h @@ -50,6 +50,7 @@ #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) @@ -79,6 +80,7 @@ #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) diff --git a/libavutil/x86/intmath.h b/libavutil/x86/intmath.h index e83971c08..40743fd13 100644 --- a/libavutil/x86/intmath.h +++ b/libavutil/x86/intmath.h @@ -47,7 +47,8 @@ static av_always_inline av_const int ff_log2_x86(unsigned int v) # endif # define ff_log2_16bit av_log2 -#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && (_MSC_VER >= 1700)) +#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 diff --git a/libavutil/x86/x86inc.asm b/libavutil/x86/x86inc.asm index 6a054a3e0..196374c34 100644 --- a/libavutil/x86/x86inc.asm +++ b/libavutil/x86/x86inc.asm @@ -337,6 +337,8 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %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 @@ -450,15 +452,16 @@ DECLARE_REG 14, R13, 120 %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 + %if xmm_regs_used > 6 + high_mm_regs movaps [rstk + stack_offset + 8], xmm6 %endif - %if xmm_regs_used > 7 + %if xmm_regs_used > 7 + high_mm_regs movaps [rstk + stack_offset + 24], xmm7 %endif - %if xmm_regs_used > 8 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 %assign %%i 8 - %rep xmm_regs_used-8 + %rep %%xmm_regs_on_stack movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i %assign %%i %%i+1 %endrep @@ -467,10 +470,11 @@ DECLARE_REG 14, R13, 120 %macro WIN64_SPILL_XMM 1 %assign xmm_regs_used %1 - ASSERT xmm_regs_used <= 16 - %if xmm_regs_used > 8 + 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_used-8)*16 + 32 + %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 @@ -479,9 +483,10 @@ DECLARE_REG 14, R13, 120 %macro WIN64_RESTORE_XMM_INTERNAL 0 %assign %%pad_size 0 - %if xmm_regs_used > 8 - %assign %%i xmm_regs_used - %rep xmm_regs_used-8 + %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 @@ -494,10 +499,10 @@ DECLARE_REG 14, R13, 120 %assign %%pad_size stack_size_padded %endif %endif - %if xmm_regs_used > 7 + %if xmm_regs_used > 7 + high_mm_regs movaps xmm7, [rsp + stack_offset - %%pad_size + 24] %endif - %if xmm_regs_used > 6 + %if xmm_regs_used > 6 + high_mm_regs movaps xmm6, [rsp + stack_offset - %%pad_size + 8] %endif %endmacro @@ -509,12 +514,12 @@ DECLARE_REG 14, R13, 120 %assign xmm_regs_used 0 %endmacro -%define has_epilogue regs_used > 7 || xmm_regs_used > 6 || mmsize == 32 || stack_size > 0 +%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 mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -538,9 +543,10 @@ DECLARE_REG 12, R15, 56 DECLARE_REG 13, R12, 64 DECLARE_REG 14, R13, 72 -%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... +%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 @@ -550,7 +556,7 @@ DECLARE_REG 14, R13, 72 DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 9 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 9 || stack_size > 0 || vzeroupper_required %macro RET 0 %if stack_size_padded > 0 @@ -561,7 +567,7 @@ DECLARE_REG 14, R13, 72 %endif %endif POP_IF_USED 14, 13, 12, 11, 10, 9 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -606,7 +612,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 3 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 3 || stack_size > 0 || vzeroupper_required %macro RET 0 %if stack_size_padded > 0 @@ -617,7 +623,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endif %endif POP_IF_USED 6, 5, 4, 3 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -727,7 +733,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %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 + %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 @@ -803,12 +809,13 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %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<<20) -%assign cpuflags_cache64 (1<<21) -%assign cpuflags_slowctz (1<<22) -%assign cpuflags_aligned (1<<23) ; not a cpu feature, but a function variant -%assign cpuflags_atom (1<<24) +%assign cpuflags_cache32 (1<<21) +%assign cpuflags_cache64 (1<<22) +%assign cpuflags_slowctz (1<<23) +%assign cpuflags_aligned (1<<24) ; not a cpu feature, but a function variant +%assign cpuflags_atom (1<<25) ; Returns a boolean value expressing whether or not the specified cpuflag is enabled. %define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) @@ -856,11 +863,12 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %endif %endmacro -; Merge mmx and sse* +; 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# -; (All 3 remain in sync through SWAP.) +; 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 @@ -870,6 +878,18 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %undef %1%2 %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 @@ -885,7 +905,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, CAT_XDEFINE nnmm, %%i, %%i %assign %%i %%i+1 %endrep - %rep 8 + %rep 24 CAT_UNDEF m, %%i CAT_UNDEF nnmm, %%i %assign %%i %%i+1 @@ -897,30 +917,62 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign avx_enabled 0 %define RESET_MM_PERMUTATION INIT_XMM %1 %define mmsize 16 - %define num_mmregs 8 - %if ARCH_X86_64 - %define num_mmregs 16 - %endif %define mova movdqa %define movu movdqu %define movh movq %define movnta movntdq + INIT_CPUFLAGS %1 + %define num_mmregs 8 + %if ARCH_X86_64 + %define num_mmregs 16 + %if cpuflag(avx512) + %define num_mmregs 32 + %endif + %endif %assign %%i 0 %rep num_mmregs CAT_XDEFINE m, %%i, xmm %+ %%i CAT_XDEFINE nnxmm, %%i, %%i %assign %%i %%i+1 %endrep - INIT_CPUFLAGS %1 + %if WIN64 + ; Swap callee-saved registers with volatile registers + AVX512_MM_PERMUTATION 6 + %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 num_mmregs 8 %if ARCH_X86_64 %define num_mmregs 16 + %if cpuflag(avx512) + %define num_mmregs 32 + %endif + %endif + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, ymm %+ %%i + CAT_XDEFINE nnymm, %%i, %%i + %assign %%i %%i+1 + %endrep + AVX512_MM_PERMUTATION +%endmacro + +%macro INIT_ZMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_ZMM %1 + %define mmsize 64 + %define num_mmregs 8 + %if ARCH_X86_64 + %define num_mmregs 32 %endif %define mova movdqa %define movu movdqu @@ -928,11 +980,12 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %define movnta movntdq %assign %%i 0 %rep num_mmregs - CAT_XDEFINE m, %%i, ymm %+ %%i - CAT_XDEFINE nnymm, %%i, %%i + CAT_XDEFINE m, %%i, zmm %+ %%i + CAT_XDEFINE nnzmm, %%i, %%i %assign %%i %%i+1 %endrep INIT_CPUFLAGS %1 + AVX512_MM_PERMUTATION %endmacro INIT_XMM @@ -941,18 +994,26 @@ INIT_XMM %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 16 +%rep 32 DECLARE_MMCAST i %assign i i+1 %endrep @@ -1087,12 +1148,17 @@ INIT_XMM ;============================================================================= %assign i 0 -%rep 16 +%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 @@ -1209,7 +1275,7 @@ INIT_XMM %endmacro %endmacro -; Instructions with both VEX and non-VEX encodings +; 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 @@ -1545,6 +1611,52 @@ 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 diff --git a/libavutil/x86/x86util.asm b/libavutil/x86/x86util.asm index e1220dfc1..d7cd99684 100644 --- a/libavutil/x86/x86util.asm +++ b/libavutil/x86/x86util.asm @@ -357,7 +357,7 @@ %endif %endmacro -%macro ABSB 2 ; source mmreg, temp mmreg (unused for ssse3) +%macro ABSB 2 ; source mmreg, temp mmreg (unused for SSSE3) %if cpuflag(ssse3) pabsb %1, %1 %else @@ -381,7 +381,7 @@ %endif %endmacro -%macro ABSD2_MMX 4 +%macro ABSD2 4 pxor %3, %3 pxor %4, %4 pcmpgtd %3, %1 @@ -475,7 +475,7 @@ %else palignr %1, %2, %3 %endif -%elif cpuflag(mmx) ; [dst,] src1, src2, imm, tmp +%else ; [dst,] src1, src2, imm, tmp %define %%dst %1 %if %0==5 %ifnidn %1, %2 @@ -799,37 +799,47 @@ pminsw %1, %3 %endmacro -%macro PMINSD_MMX 3 ; dst, src, tmp +%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_MMX 3 ; dst, src, tmp +%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_MMX 3-4 ; src/dst, min, max, tmp - PMINSD_MMX %1, %3, %4 - PMAXSD_MMX %1, %2, %4 -%endmacro - -%macro CLIPD_SSE2 3-4 ; src/dst, min (float), max (float), unused +%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 -%endmacro - -%macro CLIPD_SSE41 3-4 ; src/dst, min, max, unused - pminsd %1, %3 - pmaxsd %1, %2 +%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 @@ -880,6 +890,14 @@ %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 diff --git a/libavutil/xga_font_data.h b/libavutil/xga_font_data.h index 5e40f542e..69dc33712 100644 --- a/libavutil/xga_font_data.h +++ b/libavutil/xga_font_data.h @@ -29,7 +29,7 @@ #include #include "internal.h" -extern av_export const uint8_t avpriv_cga_font[2048]; -extern av_export const uint8_t avpriv_vga16_font[4096]; +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/libpostproc/postprocess.h b/libpostproc/postprocess.h index d180686e7..348ee7cc6 100644 --- a/libpostproc/postprocess.h +++ b/libpostproc/postprocess.h @@ -53,10 +53,6 @@ const char *postproc_license(void); #define PP_QUALITY_MAX 6 -#if FF_API_QP_TYPE -#define QP_STORE_T int8_t //deprecated -#endif - #include typedef void pp_context; diff --git a/libpostproc/version.h b/libpostproc/version.h index e8f0abe81..79eea7c24 100644 --- a/libpostproc/version.h +++ b/libpostproc/version.h @@ -28,8 +28,8 @@ #include "libavutil/avutil.h" -#define LIBPOSTPROC_VERSION_MAJOR 54 -#define LIBPOSTPROC_VERSION_MINOR 7 +#define LIBPOSTPROC_VERSION_MAJOR 55 +#define LIBPOSTPROC_VERSION_MINOR 0 #define LIBPOSTPROC_VERSION_MICRO 100 #define LIBPOSTPROC_VERSION_INT AV_VERSION_INT(LIBPOSTPROC_VERSION_MAJOR, \ @@ -42,8 +42,4 @@ #define LIBPOSTPROC_IDENT "postproc" AV_STRINGIFY(LIBPOSTPROC_VERSION) -#ifndef FF_API_QP_TYPE -#define FF_API_QP_TYPE (LIBPOSTPROC_VERSION_MAJOR < 55) -#endif - #endif /* POSTPROC_VERSION_H */ diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index 66a43c16c..9fcfff131 100644 --- a/libswresample/rematrix.c +++ b/libswresample/rematrix.c @@ -445,14 +445,23 @@ av_cold int swri_rematrix_init(SwrContext *s){ 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){ - // Only for dithering currently -// s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double)); s->native_one = av_mallocz(sizeof(int)); if (!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]; + 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; diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 74c96dce6..f076b6c8c 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -240,7 +240,7 @@ av_cold int swr_init(struct SwrContext *s){ &&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, S16/S32/S64/FLT/DBL is supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); + 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); } @@ -276,7 +276,7 @@ av_cold int swr_init(struct SwrContext *s){ && 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 s16/s32/flt/dbl\n"); + av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16p/s32p/fltp/dblp\n"); ret = AVERROR(EINVAL); goto fail; } diff --git a/libswresample/tests/.gitignore b/libswresample/tests/.gitignore new file mode 100644 index 000000000..2dc986bd0 --- /dev/null +++ b/libswresample/tests/.gitignore @@ -0,0 +1 @@ +/swresample diff --git a/libswresample/version.h b/libswresample/version.h index 6a66173f3..2640b1067 100644 --- a/libswresample/version.h +++ b/libswresample/version.h @@ -28,9 +28,9 @@ #include "libavutil/avutil.h" -#define LIBSWRESAMPLE_VERSION_MAJOR 2 -#define LIBSWRESAMPLE_VERSION_MINOR 9 -#define LIBSWRESAMPLE_VERSION_MICRO 100 +#define LIBSWRESAMPLE_VERSION_MAJOR 3 +#define LIBSWRESAMPLE_VERSION_MINOR 0 +#define LIBSWRESAMPLE_VERSION_MICRO 101 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ LIBSWRESAMPLE_VERSION_MINOR, \ diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c index ef36aec50..5ec2116bc 100644 --- a/libswscale/swscale_unscaled.c +++ b/libswscale/swscale_unscaled.c @@ -110,24 +110,6 @@ DECLARE_ALIGNED(8, static const uint8_t, dithers)[8][8][8]={ { 112, 16,104, 8,118, 22,110, 14,}, }}; -static const uint16_t dither_scale[15][16]={ -{ 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,}, -{ 2, 3, 7, 7, 13, 13, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,}, -{ 3, 3, 4, 15, 15, 29, 57, 57, 57, 113, 113, 113, 113, 113, 113, 113,}, -{ 3, 4, 4, 5, 31, 31, 61, 121, 241, 241, 241, 241, 481, 481, 481, 481,}, -{ 3, 4, 5, 5, 6, 63, 63, 125, 249, 497, 993, 993, 993, 993, 993, 1985,}, -{ 3, 5, 6, 6, 6, 7, 127, 127, 253, 505, 1009, 2017, 4033, 4033, 4033, 4033,}, -{ 3, 5, 6, 7, 7, 7, 8, 255, 255, 509, 1017, 2033, 4065, 8129,16257,16257,}, -{ 3, 5, 6, 8, 8, 8, 8, 9, 511, 511, 1021, 2041, 4081, 8161,16321,32641,}, -{ 3, 5, 7, 8, 9, 9, 9, 9, 10, 1023, 1023, 2045, 4089, 8177,16353,32705,}, -{ 3, 5, 7, 8, 10, 10, 10, 10, 10, 11, 2047, 2047, 4093, 8185,16369,32737,}, -{ 3, 5, 7, 8, 10, 11, 11, 11, 11, 11, 12, 4095, 4095, 8189,16377,32753,}, -{ 3, 5, 7, 9, 10, 12, 12, 12, 12, 12, 12, 13, 8191, 8191,16381,32761,}, -{ 3, 5, 7, 9, 10, 12, 13, 13, 13, 13, 13, 13, 14,16383,16383,32765,}, -{ 3, 5, 7, 9, 10, 12, 14, 14, 14, 14, 14, 14, 14, 15,32767,32767,}, -{ 3, 5, 7, 9, 11, 12, 14, 15, 15, 15, 15, 15, 15, 15, 16,65535,}, -}; - static void fillPlane(uint8_t *plane, int stride, int width, int height, int y, uint8_t val) @@ -1502,24 +1484,63 @@ static int packedCopyWrapper(SwsContext *c, const uint8_t *src[], } #define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\ - uint16_t scale= dither_scale[dst_depth-1][src_depth-1];\ - int shift= src_depth-dst_depth + dither_scale[src_depth-2][dst_depth-1];\ - for (i = 0; i < height; i++) {\ - const uint8_t *dither= dithers[src_depth-9][i&7];\ - for (j = 0; j < length-7; j+=8){\ - dst[j+0] = dbswap((bswap(src[j+0]) + dither[0])*scale>>shift);\ - dst[j+1] = dbswap((bswap(src[j+1]) + dither[1])*scale>>shift);\ - dst[j+2] = dbswap((bswap(src[j+2]) + dither[2])*scale>>shift);\ - dst[j+3] = dbswap((bswap(src[j+3]) + dither[3])*scale>>shift);\ - dst[j+4] = dbswap((bswap(src[j+4]) + dither[4])*scale>>shift);\ - dst[j+5] = dbswap((bswap(src[j+5]) + dither[5])*scale>>shift);\ - dst[j+6] = dbswap((bswap(src[j+6]) + dither[6])*scale>>shift);\ - dst[j+7] = dbswap((bswap(src[j+7]) + dither[7])*scale>>shift);\ + unsigned shift= src_depth-dst_depth, tmp;\ + if (c->dither == SWS_DITHER_NONE) {\ + for (i = 0; i < height; i++) {\ + for (j = 0; j < length-7; j+=8) {\ + dst[j+0] = dbswap(bswap(src[j+0])>>shift);\ + dst[j+1] = dbswap(bswap(src[j+1])>>shift);\ + dst[j+2] = dbswap(bswap(src[j+2])>>shift);\ + dst[j+3] = dbswap(bswap(src[j+3])>>shift);\ + dst[j+4] = dbswap(bswap(src[j+4])>>shift);\ + dst[j+5] = dbswap(bswap(src[j+5])>>shift);\ + dst[j+6] = dbswap(bswap(src[j+6])>>shift);\ + dst[j+7] = dbswap(bswap(src[j+7])>>shift);\ + }\ + for (; j < length; j++) {\ + dst[j] = dbswap(bswap(src[j])>>shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } else if (shiftonly) {\ + for (i = 0; i < height; i++) {\ + const uint8_t *dither= dithers[shift-1][i&7];\ + for (j = 0; j < length-7; j+=8) {\ + tmp = (bswap(src[j+0]) + dither[0])>>shift; dst[j+0] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+1]) + dither[1])>>shift; dst[j+1] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+2]) + dither[2])>>shift; dst[j+2] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+3]) + dither[3])>>shift; dst[j+3] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+4]) + dither[4])>>shift; dst[j+4] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+5]) + dither[5])>>shift; dst[j+5] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+6]) + dither[6])>>shift; dst[j+6] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+7]) + dither[7])>>shift; dst[j+7] = dbswap(tmp - (tmp>>dst_depth));\ + }\ + for (; j < length; j++) {\ + tmp = (bswap(src[j]) + dither[j&7])>>shift; dst[j] = dbswap(tmp - (tmp>>dst_depth));\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } else {\ + for (i = 0; i < height; i++) {\ + const uint8_t *dither= dithers[shift-1][i&7];\ + for (j = 0; j < length-7; j+=8) {\ + tmp = bswap(src[j+0]); dst[j+0] = dbswap((tmp - (tmp>>dst_depth) + dither[0])>>shift);\ + tmp = bswap(src[j+1]); dst[j+1] = dbswap((tmp - (tmp>>dst_depth) + dither[1])>>shift);\ + tmp = bswap(src[j+2]); dst[j+2] = dbswap((tmp - (tmp>>dst_depth) + dither[2])>>shift);\ + tmp = bswap(src[j+3]); dst[j+3] = dbswap((tmp - (tmp>>dst_depth) + dither[3])>>shift);\ + tmp = bswap(src[j+4]); dst[j+4] = dbswap((tmp - (tmp>>dst_depth) + dither[4])>>shift);\ + tmp = bswap(src[j+5]); dst[j+5] = dbswap((tmp - (tmp>>dst_depth) + dither[5])>>shift);\ + tmp = bswap(src[j+6]); dst[j+6] = dbswap((tmp - (tmp>>dst_depth) + dither[6])>>shift);\ + tmp = bswap(src[j+7]); dst[j+7] = dbswap((tmp - (tmp>>dst_depth) + dither[7])>>shift);\ + }\ + for (; j < length; j++) {\ + tmp = bswap(src[j]); dst[j] = dbswap((tmp - (tmp>>dst_depth) + dither[j&7])>>shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ }\ - for (; j < length; j++)\ - dst[j] = dbswap((bswap(src[j]) + dither[j&7])*scale>>shift);\ - dst += dstStride;\ - src += srcStride;\ } static int planarCopyWrapper(SwsContext *c, const uint8_t *src[], diff --git a/libswscale/tests/.gitignore b/libswscale/tests/.gitignore new file mode 100644 index 000000000..1a26f038c --- /dev/null +++ b/libswscale/tests/.gitignore @@ -0,0 +1,3 @@ +/colorspace +/pixdesc_query +/swscale diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c index b4b8173a3..e72c4c330 100644 --- a/libswscale/tests/swscale.c +++ b/libswscale/tests/swscale.c @@ -55,8 +55,8 @@ (x) == AV_PIX_FMT_RGB32_1 || \ (x) == AV_PIX_FMT_YUVA420P) -static uint64_t getSSD(const uint8_t *src1, const uint8_t *src2, int stride1, - int stride2, int w, int h) +static uint64_t getSSD(const uint8_t *src1, const uint8_t *src2, + int stride1, int stride2, int w, int h) { int x, y; uint64_t ssd = 0; @@ -80,7 +80,7 @@ struct Results { // test by ref -> src -> dst -> out & compare out against ref // ref & out are YV12 -static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, +static int doTest(const uint8_t * const ref[4], int refStride[4], int w, int h, enum AVPixelFormat srcFormat, enum AVPixelFormat dstFormat, int srcW, int srcH, int dstW, int dstH, int flags, struct Results *r) @@ -90,7 +90,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(dstFormat); static enum AVPixelFormat cur_srcFormat; static int cur_srcW, cur_srcH; - static uint8_t *src[4]; + static const uint8_t *src[4]; static int srcStride[4]; uint8_t *dst[4] = { 0 }; uint8_t *out[4] = { 0 }; @@ -132,7 +132,8 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, res = -1; goto end; } - sws_scale(srcContext, (const uint8_t * const*)ref, refStride, 0, h, src, srcStride); + sws_scale(srcContext, ref, refStride, 0, h, + (uint8_t * const *) src, srcStride); sws_freeContext(srcContext); cur_srcFormat = srcFormat; @@ -211,7 +212,8 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, res = -1; goto end; } - sws_scale(outContext, (const uint8_t * const*)dst, dstStride, 0, dstH, out, refStride); + sws_scale(outContext, (const uint8_t * const *) dst, dstStride, 0, dstH, + out, refStride); ssdY = getSSD(ref[0], out[0], refStride[0], refStride[0], w, h); if (hasChroma(srcFormat) && hasChroma(dstFormat)) { @@ -249,7 +251,8 @@ end: return res; } -static void selfTest(uint8_t *ref[4], int refStride[4], int w, int h, +static void selfTest(const uint8_t * const ref[4], int refStride[4], + int w, int h, enum AVPixelFormat srcFormat_in, enum AVPixelFormat dstFormat_in) { @@ -299,7 +302,8 @@ static void selfTest(uint8_t *ref[4], int refStride[4], int w, int h, } } -static int fileTest(uint8_t *ref[4], int refStride[4], int w, int h, FILE *fp, +static int fileTest(const uint8_t * const ref[4], int refStride[4], + int w, int h, FILE *fp, enum AVPixelFormat srcFormat_in, enum AVPixelFormat dstFormat_in) { @@ -362,7 +366,7 @@ int main(int argc, char **argv) const uint8_t * const rgb_src[4] = { rgb_data, NULL, NULL, NULL }; int rgb_stride[4] = { 4 * W, 0, 0, 0 }; uint8_t *data = av_malloc(4 * W * H); - uint8_t *src[4] = { data, data + W * H, data + W * H * 2, data + W * H * 3 }; + const uint8_t * const src[4] = { data, data + W * H, data + W * H * 2, data + W * H * 3 }; int stride[4] = { W, W, W, W }; int x, y; struct SwsContext *sws; @@ -418,7 +422,7 @@ bad_option: for (y = 0; y < H; y++) for (x = 0; x < W * 4; x++) rgb_data[ x + y * 4 * W] = av_lfg_get(&rand); - sws_scale(sws, rgb_src, rgb_stride, 0, H / 12, src, stride); + sws_scale(sws, rgb_src, rgb_stride, 0, H / 12, (uint8_t * const *) src, stride); sws_freeContext(sws); av_free(rgb_data); diff --git a/libswscale/utils.c b/libswscale/utils.c index dcab707de..4df09306d 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -27,7 +27,7 @@ #include #include #include -#if HAVE_SYS_MMAN_H +#if HAVE_MMAP #include #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON diff --git a/libswscale/version.h b/libswscale/version.h index 474e93b26..0393a6fe4 100644 --- a/libswscale/version.h +++ b/libswscale/version.h @@ -26,9 +26,9 @@ #include "libavutil/version.h" -#define LIBSWSCALE_VERSION_MAJOR 4 -#define LIBSWSCALE_VERSION_MINOR 8 -#define LIBSWSCALE_VERSION_MICRO 100 +#define LIBSWSCALE_VERSION_MAJOR 5 +#define LIBSWSCALE_VERSION_MINOR 0 +#define LIBSWSCALE_VERSION_MICRO 101 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ LIBSWSCALE_VERSION_MINOR, \ diff --git a/libswscale/x86/scale.asm b/libswscale/x86/scale.asm index f9781703a..83cabff72 100644 --- a/libswscale/x86/scale.asm +++ b/libswscale/x86/scale.asm @@ -364,15 +364,7 @@ cglobal hscale%1to%2_%4, %5, 10, %6, pos0, dst, w, srcmem, filter, fltpos, fltsi movd [dstq+wq*2], m0 %endif ; %3 ==/!= X %else ; %2 == 19 -%if mmsize == 8 - PMINSD_MMX m0, m2, m4 -%elif cpuflag(sse4) - pminsd m0, m2 -%else ; sse2/ssse3 - cvtdq2ps m0, m0 - minps m0, m2 - cvtps2dq m0, m0 -%endif ; mmx/sse2/ssse3/sse4 + PMINSD m0, m2, m4 %ifnidn %3, X mova [dstq+wq*(4>>wshr)], m0 %else ; %3 == X diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c index 869e7fb17..7dc2d7057 100644 --- a/libswscale/x86/swscale.c +++ b/libswscale/x86/swscale.c @@ -53,13 +53,13 @@ DECLARE_ASM_CONST(8, uint64_t, b15Mask)= 0x001F001F001F001FLL; DECLARE_ASM_CONST(8, uint64_t, g15Mask)= 0x03E003E003E003E0LL; DECLARE_ASM_CONST(8, uint64_t, r15Mask)= 0x7C007C007C007C00LL; -DECLARE_ALIGNED(8, const uint64_t, ff_M24A) = 0x00FF0000FF0000FFLL; -DECLARE_ALIGNED(8, const uint64_t, ff_M24B) = 0xFF0000FF0000FF00LL; -DECLARE_ALIGNED(8, const uint64_t, ff_M24C) = 0x0000FF0000FF0000LL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_M24A) = 0x00FF0000FF0000FFLL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_M24B) = 0xFF0000FF0000FF00LL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_M24C) = 0x0000FF0000FF0000LL; -DECLARE_ALIGNED(8, const uint64_t, ff_bgr2YOffset) = 0x1010101010101010ULL; -DECLARE_ALIGNED(8, const uint64_t, ff_bgr2UVOffset) = 0x8080808080808080ULL; -DECLARE_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_bgr2YOffset) = 0x1010101010101010ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_bgr2UVOffset) = 0x8080808080808080ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL; //MMX versions diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c index 1fe5abed9..737cbb06c 100644 --- a/libswscale/yuv2rgb.c +++ b/libswscale/yuv2rgb.c @@ -267,7 +267,11 @@ ENDYUV2RGBLINE(8, 1) PUTRGB(dst_2, py_2, 0); ENDYUV2RGBFUNC() +#if HAVE_BIGENDIAN +YUV2RGBFUNC(yuva2argb_c, uint32_t, 1) +#else YUV2RGBFUNC(yuva2rgba_c, uint32_t, 1) +#endif LOADCHROMA(0); PUTRGBA(dst_1, py_1, pa_1, 0, 24); PUTRGBA(dst_2, py_2, pa_2, 0, 24); @@ -301,7 +305,11 @@ ENDYUV2RGBLINE(8, 1) PUTRGBA(dst_2, py_2, pa_2, 0, 24); ENDYUV2RGBFUNC() +#if HAVE_BIGENDIAN +YUV2RGBFUNC(yuva2rgba_c, uint32_t, 1) +#else YUV2RGBFUNC(yuva2argb_c, uint32_t, 1) +#endif LOADCHROMA(0); PUTRGBA(dst_1, py_1, pa_1, 0, 0); PUTRGBA(dst_2, py_2, pa_2, 0, 0); diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 000000000..4766e5694 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,11 @@ +/audiogen +/audiomatch +/base64 +/data/ +/pixfmts.mak +/rotozoom +/test_copy.ffmeta +/tiny_psnr +/tiny_ssim +/videogen +/vsynth1/ diff --git a/tests/Makefile b/tests/Makefile index 278be24cc..14b960137 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,3 @@ -FFSERVER_REFFILE = $(SRC_PATH)/tests/ffserver.regression.ref - THREADS = 1 VREF = tests/vsynth1/00.pgm AREF = tests/data/asynth1.sw @@ -11,14 +9,6 @@ FFMPEG=ffmpeg$(PROGSSUF)$(EXESUF) $(AREF): CMP= -ffservertest: export PROGSUF = $(PROGSSUF) -ffservertest: ffserver$(PROGSSUF)$(EXESUF) ffmpeg$(PROGSSUF)$(EXESUF) tests/vsynth1/00.pgm tests/data/asynth1.sw - @echo - @echo "Unfortunately ffserver is broken and therefore its regression" - @echo "test fails randomly. Treat the results accordingly." - @echo - $(SRC_PATH)/tests/ffserver-regression.sh $(FFSERVER_REFFILE) $(SRC_PATH)/tests/ffserver.conf "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" - APITESTSDIR := tests/api OBJDIRS += tests/data tests/vsynth1 tests/data/filtergraphs $(APITESTSDIR)/ @@ -113,7 +103,9 @@ include $(SRC_PATH)/tests/fate/apng.mak include $(SRC_PATH)/tests/fate/atrac.mak include $(SRC_PATH)/tests/fate/audio.mak include $(SRC_PATH)/tests/fate/bmp.mak +include $(SRC_PATH)/tests/fate/build.mak include $(SRC_PATH)/tests/fate/canopus.mak +include $(SRC_PATH)/tests/fate/cbs.mak include $(SRC_PATH)/tests/fate/cdxl.mak include $(SRC_PATH)/tests/fate/checkasm.mak include $(SRC_PATH)/tests/fate/concatdec.mak diff --git a/tests/api/.gitignore b/tests/api/.gitignore new file mode 100644 index 000000000..bbab80ca7 --- /dev/null +++ b/tests/api/.gitignore @@ -0,0 +1 @@ +/*-test diff --git a/tests/audiomatch.c b/tests/audiomatch.c index ca56df09b..d44c4070e 100644 --- a/tests/audiomatch.c +++ b/tests/audiomatch.c @@ -25,23 +25,23 @@ #define FFMIN(a,b) ((a) > (b) ? (b) : (a)) #define FFMAX(a,b) ((a) > (b) ? (a) : (b)) -static int64_t fsize(FILE *f){ - int64_t end, pos= ftell(f); +static int64_t fsize(FILE *f) { + int64_t end, pos = ftell(f); fseek(f, 0, SEEK_END); end = ftell(f); fseek(f, pos, SEEK_SET); return end; } -int main(int argc, char **argv){ +int main(int argc, char **argv) { FILE *f[2]; int i, pos; int siglen, datlen; int bestpos = 0; - double bestc=0; - double sigamp= 0; + double bestc = 0; + double sigamp = 0; int16_t *signal, *data; - int maxshift= 16384; + int maxshift = 16384; if (argc < 3) { printf("audiomatch \n"); @@ -80,31 +80,35 @@ int main(int argc, char **argv){ data = malloc(datlen * sizeof(*data)); signal = malloc(siglen * sizeof(*signal)); - fread(data , 1, datlen, f[0]); - fread(signal, 1, siglen, f[1]); + if (fread(data , 1, datlen, f[0]) != datlen) + return 1; + if (fread(signal, 1, siglen, f[1]) != siglen) + return 1; datlen /= 2; siglen /= 2; - for(i=0; i sigamp * 0.94) + if (fabs(c) > sigamp * 0.94) maxshift = FFMIN(maxshift, fabs(pos)+32); - if(fabs(c)>fabs(bestc)){ - bestc= c; + if (fabs(c) > fabs(bestc)) { + bestc = c; bestpos = pos; } } printf("presig: %d postsig:%d c:%7.4f lenerr:%d\n", bestpos, datlen - siglen - bestpos, bestc / sigamp, datlen - siglen); + + return 0; } diff --git a/tests/checkasm/.gitignore b/tests/checkasm/.gitignore new file mode 100644 index 000000000..9ee0e5cfc --- /dev/null +++ b/tests/checkasm/.gitignore @@ -0,0 +1 @@ +/checkasm diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index 14916e510..352509454 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -19,9 +19,11 @@ AVCODECOBJS-$(CONFIG_AAC_DECODER) += aacpsdsp.o \ AVCODECOBJS-$(CONFIG_ALAC_DECODER) += alacdsp.o AVCODECOBJS-$(CONFIG_DCA_DECODER) += synth_filter.o AVCODECOBJS-$(CONFIG_EXR_DECODER) += exrdsp.o +AVCODECOBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuvdsp.o AVCODECOBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dsp.o AVCODECOBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_idct.o +AVCODECOBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodsp.o AVCODECOBJS-$(CONFIG_V210_ENCODER) += v210enc.o AVCODECOBJS-$(CONFIG_VP9_DECODER) += vp9dsp.o @@ -30,6 +32,8 @@ CHECKASMOBJS-$(CONFIG_AVCODEC) += $(AVCODECOBJS-yes) # libavfilter tests AVFILTEROBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o AVFILTEROBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o +AVFILTEROBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o +AVFILTEROBJS-$(CONFIG_THRESHOLD_FILTER) += vf_threshold.o CHECKASMOBJS-$(CONFIG_AVFILTER) += $(AVFILTEROBJS-yes) @@ -56,7 +60,7 @@ tests/checkasm/checkasm.o: CFLAGS += -Umain CHECKASM := tests/checkasm/checkasm$(EXESUF) $(CHECKASM): $(CHECKASMOBJS) $(FF_STATIC_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(CHECKASMOBJS) $(FF_STATIC_DEP_LIBS) $(EXTRALIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(CHECKASMOBJS) $(FF_STATIC_DEP_LIBS) $(EXTRALIBS-avcodec) $(EXTRALIBS-avfilter) $(EXTRALIBS-avutil) $(EXTRALIBS) checkasm: $(CHECKASM) diff --git a/tests/checkasm/aarch64/checkasm.S b/tests/checkasm/aarch64/checkasm.S index 75a9a5614..89f2b7754 100644 --- a/tests/checkasm/aarch64/checkasm.S +++ b/tests/checkasm/aarch64/checkasm.S @@ -22,7 +22,7 @@ #include "libavutil/aarch64/asm.S" -const register_init +const register_init, align=4 .quad 0x21f86d66c8ca00ce .quad 0x75b6ba21077c48ad .quad 0xed56bb2dcb3c7736 diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index b8b0e32db..ff0ca5b68 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -117,6 +117,9 @@ static const struct { { "hevc_add_res", checkasm_check_hevc_add_res }, { "hevc_idct", checkasm_check_hevc_idct }, #endif + #if CONFIG_HUFFYUV_DECODER + { "huffyuvdsp", checkasm_check_huffyuvdsp }, + #endif #if CONFIG_JPEG2000_DECODER { "jpeg2000dsp", checkasm_check_jpeg2000dsp }, #endif @@ -126,6 +129,9 @@ static const struct { #if CONFIG_PIXBLOCKDSP { "pixblockdsp", checkasm_check_pixblockdsp }, #endif + #if CONFIG_UTVIDEO_DECODER + { "utvideodsp", checkasm_check_utvideodsp }, + #endif #if CONFIG_V210_ENCODER { "v210enc", checkasm_check_v210enc }, #endif @@ -146,6 +152,12 @@ static const struct { #if CONFIG_COLORSPACE_FILTER { "vf_colorspace", checkasm_check_colorspace }, #endif + #if CONFIG_HFLIP_FILTER + { "vf_hflip", checkasm_check_vf_hflip }, + #endif + #if CONFIG_THRESHOLD_FILTER + { "vf_threshold", checkasm_check_vf_threshold }, + #endif #endif #if CONFIG_AVUTIL { "fixed_dsp", checkasm_check_fixed_dsp }, @@ -192,6 +204,7 @@ static const struct { { "FMA3", "fma3", AV_CPU_FLAG_FMA3 }, { "FMA4", "fma4", AV_CPU_FLAG_FMA4 }, { "AVX2", "avx2", AV_CPU_FLAG_AVX2 }, + { "AVX-512", "avx512", AV_CPU_FLAG_AVX512 }, #endif { NULL } }; diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index e5b1877dc..cfe9bfb35 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -57,12 +57,16 @@ void checkasm_check_h264pred(void); void checkasm_check_h264qpel(void); void checkasm_check_hevc_add_res(void); void checkasm_check_hevc_idct(void); +void checkasm_check_huffyuvdsp(void); void checkasm_check_jpeg2000dsp(void); void checkasm_check_llviddsp(void); void checkasm_check_pixblockdsp(void); void checkasm_check_sbrdsp(void); void checkasm_check_synth_filter(void); +void checkasm_check_utvideodsp(void); void checkasm_check_v210enc(void); +void checkasm_check_vf_hflip(void); +void checkasm_check_vf_threshold(void); void checkasm_check_vp8dsp(void); void checkasm_check_vp9dsp(void); void checkasm_check_videodsp(void); diff --git a/tests/checkasm/float_dsp.c b/tests/checkasm/float_dsp.c index 9b0a221c2..2f999a316 100644 --- a/tests/checkasm/float_dsp.c +++ b/tests/checkasm/float_dsp.c @@ -165,7 +165,8 @@ static void test_vector_dmul_scalar(const double *src0, const double *src1) call_ref(cdst, src0, src1[0], LEN); call_new(odst, src0, src1[0], LEN); for (i = 0; i < LEN; i++) { - if (!double_near_abs_eps(cdst[i], odst[i], DBL_EPSILON)) { + double t = fabs(src1[0]) + fabs(src0[i]) + fabs(src1[0] * src0[i]) + 1.0; + if (!double_near_abs_eps(cdst[i], odst[i], t * 2 * DBL_EPSILON)) { fprintf(stderr, "%d: %- .12f - %- .12f = % .12g\n", i, cdst[i], odst[i], cdst[i] - odst[i]); fail(); diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 945423703..5f73bc9f0 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -22,6 +22,7 @@ #include "checkasm.h" #include "libavcodec/avcodec.h" #include "libavcodec/h264dsp.h" +#include "libavcodec/h264data.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -223,10 +224,97 @@ static void check_idct(void) } } } - report("idct"); +} + +static void check_idct_multiple(void) +{ + LOCAL_ALIGNED_16(uint8_t, dst_full, [16 * 16 * 2]); + LOCAL_ALIGNED_16(int16_t, coef_full, [16 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst0, [16 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst1, [16 * 16 * 2]); + LOCAL_ALIGNED_16(int16_t, coef0, [16 * 16 * 2]); + LOCAL_ALIGNED_16(int16_t, coef1, [16 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, nnzc, [15 * 8]); + H264DSPContext h; + int bit_depth, i, y, func; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const int *block_offset, int16_t *block, int stride, const uint8_t nnzc[15*8]); + + for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + ff_h264dsp_init(&h, bit_depth, 1); + for (func = 0; func < 3; func++) { + void (*idct)(uint8_t *, const int *, int16_t *, int, const uint8_t[]) = NULL; + const char *name; + int sz = 4, intra = 0; + int block_offset[16] = { 0 }; + switch (func) { + case 0: + idct = h.h264_idct_add16; + name = "h264_idct_add16"; + break; + case 1: + idct = h.h264_idct_add16intra; + name = "h264_idct_add16intra"; + intra = 1; + break; + case 2: + idct = h.h264_idct8_add4; + name = "h264_idct8_add4"; + sz = 8; + break; + } + memset(nnzc, 0, 15 * 8); + memset(coef_full, 0, 16 * 16 * SIZEOF_COEF); + for (i = 0; i < 16 * 16; i += sz * sz) { + uint8_t src[8 * 8 * 2]; + uint8_t dst[8 * 8 * 2]; + int16_t coef[8 * 8 * 2]; + int index = i / sz; + int block_y = (index / 16) * sz; + int block_x = index % 16; + int offset = (block_y * 16 + block_x) * SIZEOF_PIXEL; + int nnz = rnd() % 3; + + randomize_buffers(); + if (sz == 4) + dct4x4(coef, bit_depth); + else + dct8x8(coef, bit_depth); + + for (y = 0; y < sz; y++) + memcpy(&dst_full[offset + y * 16 * SIZEOF_PIXEL], + &dst[PIXEL_STRIDE * y], sz * SIZEOF_PIXEL); + + if (nnz > 1) + nnz = sz * sz; + memcpy(&coef_full[i * SIZEOF_COEF/sizeof(coef[0])], + coef, nnz * SIZEOF_COEF); + + if (intra && nnz == 1) + nnz = 0; + + nnzc[scan8[i / 16]] = nnz; + block_offset[i / 16] = offset; + } + + if (check_func(idct, "%s_%dbpp", name, bit_depth)) { + memcpy(coef0, coef_full, 16 * 16 * SIZEOF_COEF); + memcpy(coef1, coef_full, 16 * 16 * SIZEOF_COEF); + memcpy(dst0, dst_full, 16 * 16 * SIZEOF_PIXEL); + memcpy(dst1, dst_full, 16 * 16 * SIZEOF_PIXEL); + call_ref(dst0, block_offset, coef0, 16 * SIZEOF_PIXEL, nnzc); + call_new(dst1, block_offset, coef1, 16 * SIZEOF_PIXEL, nnzc); + if (memcmp(dst0, dst1, 16 * 16 * SIZEOF_PIXEL) || + memcmp(coef0, coef1, 16 * 16 * SIZEOF_COEF)) + fail(); + bench_new(dst1, block_offset, coef1, 16 * SIZEOF_PIXEL, nnzc); + } + } + } } void checkasm_check_h264dsp(void) { check_idct(); + check_idct_multiple(); + report("idct"); } diff --git a/tests/checkasm/hevc_add_res.c b/tests/checkasm/hevc_add_res.c index 185656ae8..e92c6b427 100644 --- a/tests/checkasm/hevc_add_res.c +++ b/tests/checkasm/hevc_add_res.c @@ -61,7 +61,7 @@ static void check_add_res(HEVCDSPContext h, int bit_depth) memcpy(res1, res0, sizeof(*res0) * size); memcpy(dst1, dst0, sizeof(int16_t) * size); - if (check_func(h.add_residual[i - 2], "add_res_%dx%d_%d", block_size, block_size, bit_depth)) { + if (check_func(h.add_residual[i - 2], "hevc_add_res_%dx%d_%d", block_size, block_size, bit_depth)) { call_ref(dst0, res0, stride); call_new(dst1, res1, stride); if (memcmp(dst0, dst1, size)) diff --git a/tests/checkasm/huffyuvdsp.c b/tests/checkasm/huffyuvdsp.c new file mode 100644 index 000000000..8392022c0 --- /dev/null +++ b/tests/checkasm/huffyuvdsp.c @@ -0,0 +1,81 @@ +/* + * 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 General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with 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/intreadwrite.h" +#include "libavutil/mem.h" + +#include "libavcodec/huffyuvdsp.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + for (j = 0; j < size; j++) \ + buf[j] = rnd() & 0xFFFF; \ + } while (0) + +static void check_add_int16(HuffYUVDSPContext c, unsigned mask, int width, const char * name) +{ + uint16_t *src0 = av_mallocz(width * sizeof(uint16_t)); + uint16_t *src1 = av_mallocz(width * sizeof(uint16_t)); + uint16_t *dst0 = av_mallocz(width * sizeof(uint16_t)); + uint16_t *dst1 = av_mallocz(width * sizeof(uint16_t)); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint16_t *dst, uint16_t *src, unsigned mask, int w); + + if (!src0 || !src1 || !dst0 || !dst1) + fail(); + + randomize_buffers(src0, width); + memcpy(src1, src0, width * sizeof(uint16_t)); + + if (check_func(c.add_int16, "%s", name)) { + call_ref(dst0, src0, mask, width); + call_new(dst1, src1, mask, width); + if (memcmp(dst0, dst1, width * sizeof(uint16_t))) + fail(); + bench_new(dst1, src1, mask, width); + } + + av_free(src0); + av_free(src1); + av_free(dst0); + av_free(dst1); +} + +void checkasm_check_huffyuvdsp(void) +{ + HuffYUVDSPContext c; + int width = 16 * av_clip(rnd(), 16, 128); + + ff_huffyuvdsp_init(&c, AV_PIX_FMT_YUV422P); + + /*! test width not multiple of mmsize */ + check_add_int16(c, 65535, width, "add_int16_rnd_width"); + report("add_int16_rnd_width"); + + /*! test always with the same size (for perf test) */ + check_add_int16(c, 65535, 16*128, "add_int16_128"); + report("add_int16_128"); +} diff --git a/tests/checkasm/jpeg2000dsp.c b/tests/checkasm/jpeg2000dsp.c index 48559df08..bce534dba 100644 --- a/tests/checkasm/jpeg2000dsp.c +++ b/tests/checkasm/jpeg2000dsp.c @@ -29,43 +29,75 @@ #define randomize_buffers() \ do { \ int i; \ - for (i = 0; i < BUF_SIZE; i += 4) { \ - uint32_t r = rnd(); \ - AV_WN32A(ref0 + i, r); \ - AV_WN32A(new0 + i, r); \ - r = rnd(); \ - AV_WN32A(ref1 + i, r); \ - AV_WN32A(new1 + i, r); \ - r = rnd(); \ - AV_WN32A(ref2 + i, r); \ - AV_WN32A(new2 + i, r); \ - } \ + for (i = 0; i < BUF_SIZE*3; i++) \ + src[i] = rnd(); \ } while (0) -static void check_mct(uint8_t *ref0, uint8_t *ref1, uint8_t *ref2, - uint8_t *new0, uint8_t *new1, uint8_t *new2) { +#define randomize_buffers_float() \ + do { \ + int i; \ + for (i = 0; i < BUF_SIZE*3; i++) \ + src[i] = (float)rnd() / (UINT_MAX >> 5); \ + } while (0) + +static void check_rct_int(void) +{ + LOCAL_ALIGNED_32(int32_t, src, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(int32_t, ref, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(int32_t, new, [BUF_SIZE*3]); + int32_t *ref0 = &ref[BUF_SIZE*0], *new0 = &new[BUF_SIZE*0]; + int32_t *ref1 = &ref[BUF_SIZE*1], *new1 = &new[BUF_SIZE*1]; + int32_t *ref2 = &ref[BUF_SIZE*2], *new2 = &new[BUF_SIZE*2]; + declare_func(void, void *src0, void *src1, void *src2, int csize); randomize_buffers(); - call_ref(ref0, ref1, ref2, BUF_SIZE / sizeof(int32_t)); - call_new(new0, new1, new2, BUF_SIZE / sizeof(int32_t)); - if (memcmp(ref0, new0, BUF_SIZE) || memcmp(ref1, new1, BUF_SIZE) || - memcmp(ref2, new2, BUF_SIZE)) + memcpy(ref, src, BUF_SIZE * 3 * sizeof(*src)); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + call_ref(ref0, ref1, ref2, BUF_SIZE); + call_new(new0, new1, new2, BUF_SIZE); + if (memcmp(ref0, new0, BUF_SIZE * sizeof(*src)) || + memcmp(ref1, new1, BUF_SIZE * sizeof(*src)) || + memcmp(ref2, new2, BUF_SIZE * sizeof(*src))) fail(); - bench_new(new0, new1, new2, BUF_SIZE / sizeof(int32_t)); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + bench_new(new0, new1, new2, BUF_SIZE); +} + +static void check_ict_float(void) +{ + LOCAL_ALIGNED_32(float, src, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(float, ref, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(float, new, [BUF_SIZE*3]); + float *ref0 = &ref[BUF_SIZE*0], *new0 = &new[BUF_SIZE*0]; + float *ref1 = &ref[BUF_SIZE*1], *new1 = &new[BUF_SIZE*1]; + float *ref2 = &ref[BUF_SIZE*2], *new2 = &new[BUF_SIZE*2]; + + declare_func(void, void *src0, void *src1, void *src2, int csize); + + randomize_buffers_float(); + memcpy(ref, src, BUF_SIZE * 3 * sizeof(*src)); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + call_ref(ref0, ref1, ref2, BUF_SIZE); + call_new(new0, new1, new2, BUF_SIZE); + if (!float_near_abs_eps_array(ref0, new0, 1.0e-5, BUF_SIZE) || + !float_near_abs_eps_array(ref1, new1, 1.0e-5, BUF_SIZE) || + !float_near_abs_eps_array(ref2, new2, 1.0e-5, BUF_SIZE)) + fail(); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + bench_new(new0, new1, new2, BUF_SIZE); } void checkasm_check_jpeg2000dsp(void) { - LOCAL_ALIGNED_32(uint8_t, ref, [BUF_SIZE*3]); - LOCAL_ALIGNED_32(uint8_t, new, [BUF_SIZE*3]); Jpeg2000DSPContext h; ff_jpeg2000dsp_init(&h); if (check_func(h.mct_decode[FF_DWT53], "jpeg2000_rct_int")) - check_mct(&ref[BUF_SIZE*0], &ref[BUF_SIZE*1], &ref[BUF_SIZE*2], - &new[BUF_SIZE*0], &new[BUF_SIZE*1], &new[BUF_SIZE*2]); + check_rct_int(); + if (check_func(h.mct_decode[FF_DWT97], "jpeg2000_ict_float")) + check_ict_float(); report("mct_decode"); } diff --git a/tests/checkasm/llviddsp.c b/tests/checkasm/llviddsp.c index b1f3b83b4..4f75ffc45 100644 --- a/tests/checkasm/llviddsp.c +++ b/tests/checkasm/llviddsp.c @@ -31,23 +31,30 @@ #define randomize_buffers(buf, size) \ do { \ int j; \ + uint8_t *tmp_buf = (uint8_t *)buf;\ for (j = 0; j < size; j++) \ - buf[j] = rnd() & 0xFF; \ + tmp_buf[j] = rnd() & 0xFF; \ } while (0) +#define init_buffer(a0, a1, type, width)\ + if (!a0 || !a1)\ + fail();\ + randomize_buffers(a0, width * sizeof(type));\ + memcpy(a1, a0, width*sizeof(type));\ + static void check_add_bytes(LLVidDSPContext c, int width) { - uint8_t *src0 = av_mallocz(width); - uint8_t *src1 = av_mallocz(width); uint8_t *dst0 = av_mallocz(width); uint8_t *dst1 = av_mallocz(width); + uint8_t *src0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *src1 = av_mallocz_array(width, sizeof(uint8_t)); declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, uint8_t *src, ptrdiff_t w); - if (!src0 || !src1 || !dst0 || !dst1) + init_buffer(src0, src1, uint8_t, width); + + if (!dst0 || !dst1) fail(); - randomize_buffers(src0, width); - memcpy(src1, src0, width); if (check_func(c.add_bytes, "add_bytes")) { call_ref(dst0, src0, width); @@ -63,14 +70,151 @@ static void check_add_bytes(LLVidDSPContext c, int width) av_free(dst1); } +static void check_add_median_pred(LLVidDSPContext c, int width) { + int A0, A1, B0, B1; + uint8_t *dst0 = av_mallocz(width); + uint8_t *dst1 = av_mallocz(width); + uint8_t *src0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *src1 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *diff0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *diff1 = av_mallocz_array(width, sizeof(uint8_t)); + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const uint8_t *src1, + const uint8_t *diff, ptrdiff_t w, + int *left, int *left_top); + + init_buffer(src0, src1, uint8_t, width); + init_buffer(diff0, diff1, uint8_t, width); + + A0 = rnd() & 0xFF; + B0 = rnd() & 0xFF; + A1 = A0; + B1 = B0; + + + if (check_func(c.add_median_pred, "add_median_pred")) { + call_ref(dst0, src0, diff0, width, &A0, &B0); + call_new(dst1, src1, diff1, width, &A1, &B1); + if (memcmp(dst0, dst1, width) || (A0 != A1) || (B0 != B1)) + fail(); + bench_new(dst1, src1, diff1, width, &A1, &B1); + } + + av_free(src0); + av_free(src1); + av_free(diff0); + av_free(diff1); + av_free(dst0); + av_free(dst1); +} + +static void check_add_left_pred(LLVidDSPContext c, int width, int acc, const char * report) +{ + int res0, res1; + uint8_t *dst0 = av_mallocz(width); + uint8_t *dst1 = av_mallocz(width); + uint8_t *src0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *src1 = av_mallocz_array(width, sizeof(uint8_t)); + declare_func_emms(AV_CPU_FLAG_MMX, int, uint8_t *dst, uint8_t *src, ptrdiff_t w, int acc); + + init_buffer(src0, src1, uint8_t, width); + + if (!dst0 || !dst1) + fail(); + + if (check_func(c.add_left_pred, "%s", report)) { + res0 = call_ref(dst0, src0, width, acc); + res1 = call_new(dst1, src1, width, acc); + if ((res0 & 0xFF) != (res1 & 0xFF)||\ + memcmp(dst0, dst1, width)) + fail(); + bench_new(dst1, src1, width, acc); + } + + av_free(src0); + av_free(src1); + av_free(dst0); + av_free(dst1); +} + +static void check_add_left_pred_16(LLVidDSPContext c, unsigned mask, int width, unsigned acc, const char * report) +{ + int res0, res1; + uint16_t *dst0 = av_mallocz_array(width, sizeof(uint16_t)); + uint16_t *dst1 = av_mallocz_array(width, sizeof(uint16_t)); + uint16_t *src0 = av_mallocz_array(width, sizeof(uint16_t)); + uint16_t *src1 = av_mallocz_array(width, sizeof(uint16_t)); + declare_func_emms(AV_CPU_FLAG_MMX, int, uint16_t *dst, uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); + + init_buffer(src0, src1, uint16_t, width); + + if (!dst0 || !dst1) + fail(); + + if (check_func(c.add_left_pred_int16, "%s", report)) { + res0 = call_ref(dst0, src0, mask, width, acc); + res1 = call_new(dst1, src1, mask, width, acc); + if ((res0 &0xFFFF) != (res1 &0xFFFF)||\ + memcmp(dst0, dst1, width)) + fail(); + bench_new(dst1, src1, mask, width, acc); + } + + av_free(src0); + av_free(src1); + av_free(dst0); + av_free(dst1); +} + +static void check_add_gradient_pred(LLVidDSPContext c, int w) { + int src_size, stride; + uint8_t *src0, *src1; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *src, const ptrdiff_t stride, + const ptrdiff_t width); + + stride = w + 32; + src_size = (stride + 32) * 2; /* dsp need previous line, and ignore the start of the line */ + src0 = av_mallocz(src_size); + src1 = av_mallocz(src_size); + + init_buffer(src0, src1, uint8_t, src_size); + + if (check_func(c.add_gradient_pred, "add_gradient_pred")) { + call_ref(src0 + stride + 32, stride, w); + call_new(src1 + stride + 32, stride, w); + if (memcmp(src0, src1, stride)||/* previous line doesn't change */ + memcmp(src0+stride, src1 + stride, w + 32)) { + fail(); + } + bench_new(src1 + stride + 32, stride, w); + } + + av_free(src0); + av_free(src1); +} + void checkasm_check_llviddsp(void) { LLVidDSPContext c; int width = 16 * av_clip(rnd(), 16, 128); + int accRnd = rnd() & 0xFF; ff_llviddsp_init(&c); check_add_bytes(c, width); - report("add_bytes"); + + check_add_median_pred(c, width); + report("add_median_pred"); + + check_add_left_pred(c, width, 0, "add_left_pred_zero"); + report("add_left_pred_zero"); + + check_add_left_pred(c, width, accRnd, "add_left_pred_rnd_acc"); + report("add_left_pred_rnd_acc"); + + check_add_left_pred_16(c, 255, width, accRnd, "add_left_pred_int16"); + report("add_left_pred_int16"); + + check_add_gradient_pred(c, width); + report("add_gradient_pred"); } diff --git a/tests/checkasm/utvideodsp.c b/tests/checkasm/utvideodsp.c new file mode 100644 index 000000000..080b4287d --- /dev/null +++ b/tests/checkasm/utvideodsp.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017 Jokyo Images + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "checkasm.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/utvideodsp.h" +#include "libavutil/intreadwrite.h" + +#define WIDTH 240 +#define HEIGHT 120 +#define WIDTH_PADDED (WIDTH + 16) /* padded to 32 */ +#define BUFFER_SIZE (WIDTH_PADDED * HEIGHT) + + +#define randomize_plane(buf, type) \ + do { \ + int w, h; \ + type * tmp = buf; \ + for (h = 0; h < HEIGHT; h++) { \ + for (w = 0; w < WIDTH; w++) \ + tmp[w] = rnd() & 0xFF; \ + tmp += WIDTH_PADDED; \ + } \ + } while (0) + +#define cmp_plane(buf0, buf1, s) \ + do { \ + int h; \ + for (h = 0; h < HEIGHT; h++) { \ + if (memcmp(buf0 + h*WIDTH_PADDED, \ + buf1 + h*WIDTH_PADDED, WIDTH *s)) \ + fail();\ + } \ + } while (0) + + +#define CHECK_RESTORE(type)\ +LOCAL_ALIGNED_32(type, src_r0, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_g0, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_b0, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_r1, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_g1, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_b1, [BUFFER_SIZE]); \ +declare_func(void, type *src_r, type *src_g, type *src_b, \ + ptrdiff_t linesize_r, ptrdiff_t linesize_g, \ + ptrdiff_t linesize_b, int width, int height); \ +memset(src_r0, 0, BUFFER_SIZE * sizeof(type)); \ +memset(src_g0, 0, BUFFER_SIZE * sizeof(type)); \ +memset(src_b0, 0, BUFFER_SIZE * sizeof(type)); \ +randomize_plane(src_r0, type); \ +randomize_plane(src_g0, type); \ +randomize_plane(src_b0, type); \ +memcpy(src_r1, src_r0, BUFFER_SIZE * sizeof(type)); \ +memcpy(src_g1, src_g0, BUFFER_SIZE * sizeof(type)); \ +memcpy(src_b1, src_b0, BUFFER_SIZE * sizeof(type)); \ +call_ref(src_r0, src_g0, src_b0, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT);\ +call_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT);\ +cmp_plane(src_r0, src_r1, sizeof(type)); \ +cmp_plane(src_g0, src_g1, sizeof(type)); \ +cmp_plane(src_b0, src_b1, sizeof(type)); \ +bench_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT) + +static void check_restore_rgb_planes(void) { + CHECK_RESTORE(uint8_t); +} + +static void check_restore_rgb_planes10(void) { + CHECK_RESTORE(uint16_t); +} + +void checkasm_check_utvideodsp(void) +{ + UTVideoDSPContext h; + + ff_utvideodsp_init(&h); + + if (check_func(h.restore_rgb_planes, "restore_rgb_planes")) + check_restore_rgb_planes(); + + report("restore_rgb_planes"); + + if (check_func(h.restore_rgb_planes10, "restore_rgb_planes10")) + check_restore_rgb_planes10(); + + report("restore_rgb_planes10"); +} diff --git a/tests/checkasm/vf_hflip.c b/tests/checkasm/vf_hflip.c new file mode 100644 index 000000000..6bb4d09d6 --- /dev/null +++ b/tests/checkasm/vf_hflip.c @@ -0,0 +1,76 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "checkasm.h" +#include "libavfilter/hflip.h" +#include "libavutil/intreadwrite.h" + +#define WIDTH 256 +#define WIDTH_PADDED 256 + 32 + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + uint8_t *tmp_buf = (uint8_t *)buf;\ + for (j = 0; j < size; j++) \ + tmp_buf[j] = rnd() & 0xFF; \ + } while (0) + +static void check_hflip(int step, const char * report_name){ + LOCAL_ALIGNED_32(uint8_t, src, [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, dst_ref, [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, dst_new, [WIDTH_PADDED]); + int w = WIDTH; + int i; + int step_array[4] = {1, 1, 1, 1}; + FlipContext s; + + declare_func(void, const uint8_t *src, uint8_t *dst, int w); + + memset(src, 0, WIDTH_PADDED); + memset(dst_ref, 0, WIDTH_PADDED); + memset(dst_new, 0, WIDTH_PADDED); + randomize_buffers(src, WIDTH_PADDED); + + if (step == 2) { + w /= 2; + for (i = 0; i < 4; i++) + step_array[i] = step; + } + + ff_hflip_init(&s, step_array, 4); + + if (check_func(s.flip_line[0], "hflip_%s", report_name)) { + for (i = 1; i < w; i++) { + call_ref(src + (w - 1) * step, dst_ref, i); + call_new(src + (w - 1) * step, dst_new, i); + if (memcmp(dst_ref, dst_new, i * step)) + fail(); + } + bench_new(src + (w - 1) * step, dst_new, w); + } +} +void checkasm_check_vf_hflip(void) +{ + check_hflip(1, "byte"); + report("hflip_byte"); + + check_hflip(2, "short"); + report("hflip_short"); +} diff --git a/tests/checkasm/vf_threshold.c b/tests/checkasm/vf_threshold.c new file mode 100644 index 000000000..5a2fc0e4e --- /dev/null +++ b/tests/checkasm/vf_threshold.c @@ -0,0 +1,85 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "checkasm.h" +#include "libavfilter/threshold.h" +#include "libavutil/intreadwrite.h" + +#define WIDTH 256 +#define WIDTH_PADDED 256 + 32 + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + uint8_t *tmp_buf = (uint8_t *)buf;\ + for (j = 0; j < size; j++) \ + tmp_buf[j] = rnd() & 0xFF; \ + } while (0) + +static void check_threshold(int depth){ + LOCAL_ALIGNED_32(uint8_t, in , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, threshold, [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, min , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, max , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, out_ref , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, out_new , [WIDTH_PADDED]); + ptrdiff_t line_size = WIDTH_PADDED; + int w = WIDTH; + + declare_func(void, const uint8_t *in, const uint8_t *threshold, + const uint8_t *min, const uint8_t *max, uint8_t *out, + ptrdiff_t ilinesize, ptrdiff_t tlinesize, + ptrdiff_t flinesize, ptrdiff_t slinesize, + ptrdiff_t olinesize, int w, int h); + + ThresholdContext s; + s.depth = depth; + ff_threshold_init(&s); + + memset(in, 0, WIDTH_PADDED); + memset(threshold, 0, WIDTH_PADDED); + memset(min, 0, WIDTH_PADDED); + memset(max, 0, WIDTH_PADDED); + memset(out_ref, 0, WIDTH_PADDED); + memset(out_new, 0, WIDTH_PADDED); + randomize_buffers(in, WIDTH); + randomize_buffers(threshold, WIDTH); + randomize_buffers(min, WIDTH); + randomize_buffers(max, WIDTH); + + if (depth == 16) + w /= 2; + + if (check_func(s.threshold, "threshold%d", depth)) { + call_ref(in, threshold, min, max, out_ref, line_size, line_size, line_size, line_size, line_size, w, 1); + call_new(in, threshold, min, max, out_new, line_size, line_size, line_size, line_size, line_size, w, 1); + if (memcmp(out_ref, out_new, WIDTH)) + fail(); + bench_new(in, threshold, min, max, out_new, line_size, line_size, line_size, line_size, line_size, w, 1); + } +} + +void checkasm_check_vf_threshold(void) +{ + check_threshold(8); + report("threshold8"); + + check_threshold(16); + report("threshold16"); +} diff --git a/tests/fate-run.sh b/tests/fate-run.sh index 4641640d4..05f4ca5e2 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -127,15 +127,15 @@ ffmpeg(){ } framecrc(){ - ffmpeg "$@" -flags +bitexact -fflags +bitexact -f framecrc - + ffmpeg "$@" -bitexact -f framecrc - } ffmetadata(){ - ffmpeg "$@" -flags +bitexact -fflags +bitexact -f ffmetadata - + ffmpeg "$@" -bitexact -f ffmetadata - } framemd5(){ - ffmpeg "$@" -flags +bitexact -fflags +bitexact -f framemd5 - + ffmpeg "$@" -bitexact -f framemd5 - } crc(){ @@ -160,7 +160,7 @@ pcm(){ fmtstdout(){ fmt=$1 shift 1 - ffmpeg -flags +bitexact -fflags +bitexact "$@" -f $fmt - + ffmpeg -bitexact "$@" -f $fmt - } enc_dec_pcm(){ @@ -173,7 +173,7 @@ enc_dec_pcm(){ cleanfiles=$encfile encfile=$(target_path ${encfile}) ffmpeg -i $src_file "$@" -f $out_fmt -y ${encfile} || return - ffmpeg -flags +bitexact -fflags +bitexact -i ${encfile} -c:a pcm_${pcm_fmt} -fflags +bitexact -f ${dec_fmt} - + ffmpeg -bitexact -i ${encfile} -c:a pcm_${pcm_fmt} -fflags +bitexact -f ${dec_fmt} - } FLAGS="-flags +bitexact -sws_flags +accurate_rnd+bitexact -fflags +bitexact" @@ -294,16 +294,16 @@ gapless(){ cleanfiles="$cleanfiles $decfile1 $decfile2 $decfile3" # test packet data - ffmpeg $extra_args -i "$sample" -flags +bitexact -fflags +bitexact -c:a copy -f framecrc -y $decfile1 + ffmpeg $extra_args -i "$sample" -bitexact -c:a copy -f framecrc -y $decfile1 do_md5sum $decfile1 # test decoded (and cut) data - ffmpeg $extra_args -i "$sample" -flags +bitexact -fflags +bitexact -f wav md5: + ffmpeg $extra_args -i "$sample" -bitexact -f wav md5: # the same as above again, with seeking to the start - ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -flags +bitexact -fflags +bitexact -c:a copy -f framecrc -y $decfile2 + ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -bitexact -c:a copy -f framecrc -y $decfile2 do_md5sum $decfile2 - ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -flags +bitexact -fflags +bitexact -f wav md5: + ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -bitexact -f wav md5: # test packet data, with seeking to a specific position - ffmpeg $extra_args -ss 5 -seek_timestamp 1 -i "$sample" -flags +bitexact -fflags +bitexact -c:a copy -f framecrc -y $decfile3 + ffmpeg $extra_args -ss 5 -seek_timestamp 1 -i "$sample" -bitexact -c:a copy -f framecrc -y $decfile3 do_md5sum $decfile3 } @@ -316,7 +316,7 @@ gaplessenc(){ cleanfiles="$cleanfiles $file1" # test data after reencoding - ffmpeg -i "$sample" -flags +bitexact -fflags +bitexact -map 0:a -c:a $codec -f $format -y "$file1" + ffmpeg -i "$sample" -bitexact -map 0:a -c:a $codec -f $format -y "$file1" probegaplessinfo "$file1" } @@ -328,7 +328,7 @@ audio_match(){ decfile="${outdir}/${test}.wav" cleanfiles="$cleanfiles $decfile" - ffmpeg -i "$sample" -flags +bitexact -fflags +bitexact $extra_args -y $decfile + ffmpeg -i "$sample" -bitexact $extra_args -y $decfile tests/audiomatch $decfile $trefile } @@ -352,6 +352,10 @@ concat(){ fi } +null(){ + : +} + mkdir -p "$outdir" # Disable globbing: command arguments may contain globbing characters and diff --git a/tests/fate/aac.mak b/tests/fate/aac.mak index e8cbcef54..bd283225c 100644 --- a/tests/fate/aac.mak +++ b/tests/fate/aac.mak @@ -154,7 +154,7 @@ fate-aac-aref-encode: CMD = enc_dec_pcm adts wav s16le $(REF) -c:a aac -aac_is 0 fate-aac-aref-encode: CMP = stddev fate-aac-aref-encode: REF = ./tests/data/asynth-44100-2.wav fate-aac-aref-encode: CMP_SHIFT = -4096 -fate-aac-aref-encode: CMP_TARGET = 669 +fate-aac-aref-encode: CMP_TARGET = 596 fate-aac-aref-encode: SIZE_TOLERANCE = 2464 fate-aac-aref-encode: FUZZ = 89 @@ -163,7 +163,7 @@ fate-aac-ln-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-ref fate-aac-ln-encode: CMP = stddev fate-aac-ln-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-ln-encode: CMP_SHIFT = -4096 -fate-aac-ln-encode: CMP_TARGET = 61 +fate-aac-ln-encode: CMP_TARGET = 72 fate-aac-ln-encode: SIZE_TOLERANCE = 3560 fate-aac-ln-encode: FUZZ = 30 @@ -172,7 +172,7 @@ fate-aac-ln-encode-128k: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audi fate-aac-ln-encode-128k: CMP = stddev fate-aac-ln-encode-128k: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-ln-encode-128k: CMP_SHIFT = -4096 -fate-aac-ln-encode-128k: CMP_TARGET = 800 +fate-aac-ln-encode-128k: CMP_TARGET = 622 fate-aac-ln-encode-128k: SIZE_TOLERANCE = 3560 fate-aac-ln-encode-128k: FUZZ = 5 @@ -181,7 +181,7 @@ fate-aac-pns-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-re fate-aac-pns-encode: CMP = stddev fate-aac-pns-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-pns-encode: CMP_SHIFT = -4096 -fate-aac-pns-encode: CMP_TARGET = 616 +fate-aac-pns-encode: CMP_TARGET = 655 fate-aac-pns-encode: SIZE_TOLERANCE = 3560 fate-aac-pns-encode: FUZZ = 74 @@ -190,7 +190,7 @@ fate-aac-tns-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-re fate-aac-tns-encode: CMP = stddev fate-aac-tns-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-tns-encode: CMP_SHIFT = -4096 -fate-aac-tns-encode: CMP_TARGET = 817 +fate-aac-tns-encode: CMP_TARGET = 637 fate-aac-tns-encode: FUZZ = 7 fate-aac-tns-encode: SIZE_TOLERANCE = 3560 @@ -199,7 +199,7 @@ fate-aac-is-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-ref fate-aac-is-encode: CMP = stddev fate-aac-is-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-is-encode: CMP_SHIFT = -4096 -fate-aac-is-encode: CMP_TARGET = 615 +fate-aac-is-encode: CMP_TARGET = 514 fate-aac-is-encode: SIZE_TOLERANCE = 3560 fate-aac-is-encode: FUZZ = 10 @@ -208,26 +208,17 @@ fate-aac-ms-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-ref fate-aac-ms-encode: CMP = stddev fate-aac-ms-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-ms-encode: CMP_SHIFT = -4096 -fate-aac-ms-encode: CMP_TARGET = 675 +fate-aac-ms-encode: CMP_TARGET = 558 fate-aac-ms-encode: SIZE_TOLERANCE = 3560 fate-aac-ms-encode: FUZZ = 15 -FATE_AAC_ENCODE += fate-aac-ltp-encode -fate-aac-ltp-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav -strict -2 -c:a aac -profile:a aac_ltp -aac_pns 0 -aac_is 0 -aac_ms 0 -aac_tns 0 -b:a 36k -fflags +bitexact -flags +bitexact -fate-aac-ltp-encode: CMP = stddev -fate-aac-ltp-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav -fate-aac-ltp-encode: CMP_SHIFT = -4096 -fate-aac-ltp-encode: CMP_TARGET = 1270 -fate-aac-ltp-encode: SIZE_TOLERANCE = 3560 -fate-aac-ltp-encode: FUZZ = 17 - #Ticket1784 FATE_AAC_ENCODE += fate-aac-yoraw-encode fate-aac-yoraw-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-reference/yo.raw-short.wav -c:a aac -fflags +bitexact -flags +bitexact fate-aac-yoraw-encode: CMP = stddev fate-aac-yoraw-encode: REF = $(SAMPLES)/audio-reference/yo.raw-short.wav fate-aac-yoraw-encode: CMP_SHIFT = -12288 -fate-aac-yoraw-encode: CMP_TARGET = 259 +fate-aac-yoraw-encode: CMP_TARGET = 226 fate-aac-yoraw-encode: SIZE_TOLERANCE = 3560 fate-aac-yoraw-encode: FUZZ = 17 @@ -237,7 +228,7 @@ fate-aac-pred-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-r fate-aac-pred-encode: CMP = stddev fate-aac-pred-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-pred-encode: CMP_SHIFT = -4096 -fate-aac-pred-encode: CMP_TARGET = 841 +fate-aac-pred-encode: CMP_TARGET = 662 fate-aac-pred-encode: FUZZ = 12 fate-aac-pred-encode: SIZE_TOLERANCE = 3560 diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak index 5c3fea90c..80d26de0f 100644 --- a/tests/fate/acodec.mak +++ b/tests/fate/acodec.mak @@ -104,14 +104,14 @@ fate-acodec-dca: tests/data/asynth-44100-2.wav fate-acodec-dca: SRC = tests/data/asynth-44100-2.wav fate-acodec-dca: CMD = md5 -i $(TARGET_PATH)/$(SRC) -c:a dca -strict -2 -f dts -flags +bitexact fate-acodec-dca: CMP = oneline -fate-acodec-dca: REF = 7cd79a3717943a06b217f1130223a86f +fate-acodec-dca: REF = 2aa580ac67820fce4f581b96ebb34acc FATE_ACODEC-$(call ENCDEC, DCA, WAV) += fate-acodec-dca2 fate-acodec-dca2: CMD = enc_dec_pcm dts wav s16le $(SRC) -c:a dca -strict -2 -flags +bitexact fate-acodec-dca2: REF = $(SRC) fate-acodec-dca2: CMP = stddev fate-acodec-dca2: CMP_SHIFT = -2048 -fate-acodec-dca2: CMP_TARGET = 527 +fate-acodec-dca2: CMP_TARGET = 535 fate-acodec-dca2: SIZE_TOLERANCE = 1632 FATE_ACODEC-$(call ENCDEC, FLAC, FLAC) += fate-acodec-flac fate-acodec-flac-exact-rice diff --git a/tests/fate/avformat.mak b/tests/fate/avformat.mak index c9ea99ad1..a12f9ccc7 100644 --- a/tests/fate/avformat.mak +++ b/tests/fate/avformat.mak @@ -9,7 +9,6 @@ FATE_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp FATE_LAVF-$(call ENCDEC, PCM_S16BE, CAF) += caf FATE_LAVF-$(call ENCDEC, DPX, IMAGE2) += dpx FATE_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt -FATE_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm FATE_LAVF-$(call ENCDEC, FITS, FITS) += fits FATE_LAVF-$(call ENCDEC, RAWVIDEO, FILMSTRIP) += flm FATE_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt diff --git a/tests/fate/build.mak b/tests/fate/build.mak new file mode 100644 index 000000000..f97f9ebe5 --- /dev/null +++ b/tests/fate/build.mak @@ -0,0 +1,17 @@ +FATE_BUILD += fate-build-alltools +fate-build-alltools: alltools + +FATE_BUILD += fate-build-checkheaders +fate-build-checkheaders: checkheaders + +FATE_BUILD += fate-build-examples +fate-build-examples: examples + +FATE_BUILD += fate-build-testprogs +fate-build-testprogs: testprogs + +$(FATE_BUILD): CMD = null +$(FATE_BUILD): CMP = null + +# FATE += $(FATE_BUILD) +fate-build: $(FATE_BUILD) diff --git a/tests/fate/cbs.mak b/tests/fate/cbs.mak new file mode 100644 index 000000000..fc5967e6f --- /dev/null +++ b/tests/fate/cbs.mak @@ -0,0 +1,79 @@ +# Read/write tests: this uses the codec metadata filter - with no +# arguments, it decomposes the stream fully and then recomposes it +# without making any changes. + +fate-cbs: fate-cbs-h264 fate-cbs-hevc fate-cbs-mpeg2 + +FATE_CBS_DEPS = $(call ALLYES, $(1)_DEMUXER $(1)_PARSER $(2)_METADATA_BSF $(3)_DECODER $(3)_MUXER) + +define FATE_CBS_TEST +# (codec, test_name, sample_file, output_format) +FATE_CBS_$(1) += fate-cbs-$(1)-$(2) +fate-cbs-$(1)-$(2): CMD = md5 -i $(TARGET_SAMPLES)/$(3) -c:v copy -bsf:v $(1)_metadata -f $(4) +endef + +# H.264 read/write + +FATE_CBS_H264_SAMPLES = \ + SVA_Base_B.264 \ + BASQP1_Sony_C.jsv \ + FM1_BT_B.h264 \ + CVFC1_Sony_C.jsv \ + AUD_MW_E.264 \ + CVBS3_Sony_C.jsv \ + MR1_BT_A.h264 \ + CVWP1_TOSHIBA_E.264 \ + CVNLFI1_Sony_C.jsv \ + Sharp_MP_PAFF_1r2.jvt \ + CVMANL1_TOSHIBA_B.264 \ + sp1_bt_a.h264 \ + CVSE2_Sony_B.jsv \ + CABACI3_Sony_B.jsv + +$(foreach N,$(FATE_CBS_H264_SAMPLES),$(eval $(call FATE_CBS_TEST,h264,$(basename $(N)),h264-conformance/$(N),h264))) + +FATE_CBS_H264-$(call FATE_CBS_DEPS, H264, H264, H264) = $(FATE_CBS_h264) +FATE_SAMPLES_AVCONV += $(FATE_CBS_H264-yes) +fate-cbs-h264: $(FATE_CBS_H264-yes) + +# H.265 read/write + +FATE_CBS_HEVC_SAMPLES = \ + STRUCT_A_Samsung_5.bit \ + WP_A_Toshiba_3.bit \ + SLIST_A_Sony_4.bit \ + SLIST_D_Sony_9.bit \ + CAINIT_E_SHARP_3.bit \ + CAINIT_H_SHARP_3.bit \ + TILES_B_Cisco_1.bit \ + WPP_A_ericsson_MAIN_2.bit \ + WPP_F_ericsson_MAIN_2.bit \ + ipcm_E_NEC_2.bit \ + NUT_A_ericsson_5.bit \ + PICSIZE_A_Bossen_1.bit \ + PICSIZE_B_Bossen_1.bit \ + RPS_A_docomo_4.bit \ + RPS_E_qualcomm_5.bit \ + LTRPSPS_A_Qualcomm_1.bit \ + RPLM_A_qualcomm_4.bit \ + CONFWIN_A_Sony_1.bit \ + HRD_A_Fujitsu_2.bit + +$(foreach N,$(FATE_CBS_HEVC_SAMPLES),$(eval $(call FATE_CBS_TEST,hevc,$(basename $(N)),hevc-conformance/$(N),hevc))) + +FATE_CBS_HEVC-$(call FATE_CBS_DEPS, HEVC, HEVC, HEVC) = $(FATE_CBS_hevc) +FATE_SAMPLES_AVCONV += $(FATE_CBS_HEVC-yes) +fate-cbs-hevc: $(FATE_CBS_HEVC-yes) + +# MPEG-2 read/write + +FATE_CBS_MPEG2_SAMPLES = \ + hhi_burst_422_short.bits \ + sony-ct3.bs \ + tcela-6.bits + +$(foreach N,$(FATE_CBS_MPEG2_SAMPLES),$(eval $(call FATE_CBS_TEST,mpeg2,$(basename $(N)),mpeg2/$(N),mpeg2video))) + +FATE_CBS_MPEG2-$(call FATE_CBS_DEPS, MPEGVIDEO, MPEG2, MPEG2VIDEO) = $(FATE_CBS_mpeg2) +FATE_SAMPLES_AVCONV += $(FATE_CBS_MPEG2-yes) +fate-cbs-mpeg2: $(FATE_CBS_MPEG2-yes) diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak index fbf60e984..9216c71cb 100644 --- a/tests/fate/checkasm.mak +++ b/tests/fate/checkasm.mak @@ -22,6 +22,8 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp \ fate-checkasm-v210enc \ fate-checkasm-vf_blend \ fate-checkasm-vf_colorspace \ + fate-checkasm-vf_hflip \ + fate-checkasm-vf_threshold \ fate-checkasm-videodsp \ fate-checkasm-vp8dsp \ fate-checkasm-vp9dsp \ @@ -30,5 +32,5 @@ $(FATE_CHECKASM): tests/checkasm/checkasm$(EXESUF) $(FATE_CHECKASM): CMD = run tests/checkasm/checkasm --test=$(@:fate-checkasm-%=%) $(FATE_CHECKASM): CMP = null -FATE-$(CONFIG_STATIC) += $(FATE_CHECKASM) +FATE += $(FATE_CHECKASM) fate-checkasm: $(FATE_CHECKASM) diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak index d8f2e7159..0975af261 100644 --- a/tests/fate/ffmpeg.mak +++ b/tests/fate/ffmpeg.mak @@ -26,6 +26,14 @@ fate-mapchan: $(FATE_MAPCHAN) FATE_FFMPEG-$(CONFIG_COLOR_FILTER) += fate-ffmpeg-filter_complex fate-ffmpeg-filter_complex: CMD = framecrc -filter_complex color=d=1:r=5 -fflags +bitexact +# Ticket 6603 +FATE_FFMPEG-$(call ALLYES, AEVALSRC_FILTER ASETNSAMPLES_FILTER AC3_FIXED_ENCODER) += fate-ffmpeg-filter_complex_audio +fate-ffmpeg-filter_complex_audio: CMD = framecrc -filter_complex "aevalsrc=0:d=0.1,asetnsamples=1537" -c ac3_fixed + +# Ticket 6375, use case of NoX +FATE_SAMPLES_FFMPEG-$(call ALLYES, MOV_DEMUXER PNG_DECODER ALAC_DECODER PCM_S16LE_ENCODER RAWVIDEO_ENCODER) += fate-ffmpeg-attached_pics +fate-ffmpeg-attached_pics: CMD = threads=2 framecrc -i $(TARGET_SAMPLES)/lossless-audio/inside.m4a -c:a pcm_s16le -max_muxing_queue_size 16 + FATE_SAMPLES_FFMPEG-$(CONFIG_COLORKEY_FILTER) += fate-ffmpeg-filter_colorkey fate-ffmpeg-filter_colorkey: tests/data/filtergraphs/colorkey fate-ffmpeg-filter_colorkey: CMD = framecrc -idct simple -fflags +bitexact -flags +bitexact -sws_flags +accurate_rnd+bitexact -i $(TARGET_SAMPLES)/cavs/cavs.mpg -fflags +bitexact -flags +bitexact -sws_flags +accurate_rnd+bitexact -i $(TARGET_SAMPLES)/lena.pnm -an -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/colorkey -sws_flags +accurate_rnd+bitexact -fflags +bitexact -flags +bitexact -qscale 2 -frames:v 10 diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak index c19f301ff..bf6e2c6f8 100644 --- a/tests/fate/filter-video.mak +++ b/tests/fate/filter-video.mak @@ -113,6 +113,10 @@ FATE_FILTER-$(call ALLYES, FRAMERATE_FILTER TESTSRC2_FILTER) += fate-filter-fram fate-filter-framerate-up: CMD = framecrc -lavfi testsrc2=r=2:d=10,framerate=fps=10 -t 1 fate-filter-framerate-down: CMD = framecrc -lavfi testsrc2=r=2:d=10,framerate=fps=1 -t 1 +FATE_FILTER-$(call ALLYES, FRAMERATE_FILTER TESTSRC2_FILTER FORMAT_FILTER) += fate-filter-framerate-12bit-up fate-filter-framerate-12bit-down +fate-filter-framerate-12bit-up: CMD = framecrc -lavfi testsrc2=r=50:d=1,format=pix_fmts=yuv422p12le,framerate=fps=60 -t 1 -pix_fmt yuv422p12le +fate-filter-framerate-12bit-down: CMD = framecrc -lavfi testsrc2=r=60:d=1,format=pix_fmts=yuv422p12le,framerate=fps=50 -t 1 -pix_fmt yuv422p12le + FATE_FILTER_VSYNTH-$(CONFIG_BOXBLUR_FILTER) += fate-filter-boxblur fate-filter-boxblur: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf boxblur=2:1 diff --git a/tests/fate/fits.mak b/tests/fate/fits.mak index 3d58f9880..113498cf7 100644 --- a/tests/fate/fits.mak +++ b/tests/fate/fits.mak @@ -8,7 +8,7 @@ tests/data/fits-multi.fits: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data map.tests/data/lena-gray.fits := gray8 map.tests/data/lena-gbrp.fits := rgb24 map.tests/data/lena-gbrp16.fits := rgb48 -map.tests/data/lena-gbrap16.fits := rgba64 +map.tests/data/lena-gbrap16le.fits := rgba64 tests/data/lena%.fits: TAG = GEN tests/data/lena%.fits: NAME = $(map.$(@)) @@ -18,16 +18,16 @@ tests/data/lena%.fits: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data -y $(TARGET_PATH)/$(@) 2>/dev/null FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-ext_data_min_max -fate-fitsdec-ext_data_min_max: CMD = framecrc -i $(TARGET_SAMPLES)/fits/x0cj010ct_d0h.fit -pix_fmt gray16 +fate-fitsdec-ext_data_min_max: CMD = framecrc -i $(TARGET_SAMPLES)/fits/x0cj010ct_d0h.fit -pix_fmt gray16le FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-blank_bitpix32 -fate-fitsdec-blank_bitpix32: CMD = framecrc -blank_value 65535 -i $(TARGET_SAMPLES)/fits/file008.fits -pix_fmt gray16 +fate-fitsdec-blank_bitpix32: CMD = framecrc -blank_value 65535 -i $(TARGET_SAMPLES)/fits/file008.fits -pix_fmt gray16le FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-bitpix-32 -fate-fitsdec-bitpix-32: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0005.fits -pix_fmt gray16 +fate-fitsdec-bitpix-32: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0005.fits -pix_fmt gray16le FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-bitpix-64 -fate-fitsdec-bitpix-64: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0006.fits -pix_fmt gray16 +fate-fitsdec-bitpix-64: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0006.fits -pix_fmt gray16le FATE_FITS_DEC-$(call ALLYES, GIF_DEMUXER FITS_DEMUXER GIF_DECODER FITS_DECODER FITS_ENCODER FITS_MUXER) += fate-fitsdec-multi fate-fitsdec-multi: tests/data/fits-multi.fits @@ -37,7 +37,7 @@ fate-fitsdec%: PIXFMT = $(word 3, $(subst -, ,$(@))) fate-fitsdec%: SRC = $(TARGET_PATH)/tests/data/lena-$(PIXFMT).fits fate-fitsdec%: CMD = framecrc -i $(SRC) -pix_fmt $(PIXFMT) -FATE_FITS_DEC_PIXFMT = gray gbrp gbrp16 gbrap16 +FATE_FITS_DEC_PIXFMT = gray gbrp gbrp16 gbrap16le $(FATE_FITS_DEC_PIXFMT:%=fate-fitsdec-%): fate-fitsdec-%: tests/data/lena-%.fits FATE_FITS_DEC-$(call ALLYES, FITS_DEMUXER IMAGE2_DEMUXER FITS_DECODER PNG_DECODER FITS_ENCODER FITS_MUXER) += $(FATE_FITS_DEC_PIXFMT:%=fate-fitsdec-%) diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak index 043e1f2d1..1839b9b44 100644 --- a/tests/fate/h264.mak +++ b/tests/fate/h264.mak @@ -195,6 +195,7 @@ FATE_H264 := $(FATE_H264:%=fate-h264-conformance-%) \ fate-h264-lossless \ fate-h264-3386 \ fate-h264-missing-frame \ + fate-h264-ref-pic-mod-overflow \ FATE_H264-$(call DEMDEC, H264, H264) += $(FATE_H264) FATE_H264-$(call DEMDEC, MOV, H264) += fate-h264-crop-to-container @@ -434,6 +435,7 @@ fate-h264-intra-refresh-recovery: CMD = framecrc -i $(TARGET_SAM fate-h264-invalid-ref-mod: CMD = framecrc -i $(TARGET_SAMPLES)/h264/h264refframeregression.mp4 -an -frames 10 -pix_fmt yuv420p10le fate-h264-lossless: CMD = framecrc -i $(TARGET_SAMPLES)/h264/lossless.h264 fate-h264-mixed-nal-coding: CMD = framecrc -i $(TARGET_SAMPLES)/h264/mixed-nal-coding.mp4 +fate-h264-ref-pic-mod-overflow: CMD = framecrc -i $(TARGET_SAMPLES)/h264/ref-pic-mod-overflow.h264 fate-h264-twofields-packet: CMD = framecrc -i $(TARGET_SAMPLES)/h264/twofields_packet.mp4 -an -frames 30 fate-h264-unescaped-extradata: CMD = framecrc -i $(TARGET_SAMPLES)/h264/unescaped_extradata.mp4 -an -frames 10 fate-h264-3386: CMD = framecrc -i $(TARGET_SAMPLES)/h264/bbc2.sample.h264 diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak index 2e798eca6..184349e5d 100644 --- a/tests/fate/hevc.mak +++ b/tests/fate/hevc.mak @@ -168,6 +168,7 @@ HEVC_SAMPLES_444_8BIT = \ HEVC_SAMPLES_444_12BIT = \ IPCM_B_RExt_NEC \ PERSIST_RPARAM_A_RExt_Sony_1\ + PERSIST_RPARAM_A_RExt_Sony_3\ SAO_A_RExt_MediaTek_1 \ @@ -187,7 +188,7 @@ HEVC_SAMPLES_444_12BIT = \ define FATE_HEVC_TEST FATE_HEVC += fate-hevc-conformance-$(1) -fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit +fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv420p endef define FATE_HEVC_TEST_10BIT @@ -207,7 +208,7 @@ endef define FATE_HEVC_TEST_444_8BIT FATE_HEVC += fate-hevc-conformance-$(1) -fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit +fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv444p endef define FATE_HEVC_TEST_444_12BIT @@ -239,6 +240,9 @@ fate-hevc-bsf-mp4toannexb: CMD = md5 -i $(TARGET_PATH)/tests/data/hevc-mp4.mov - fate-hevc-bsf-mp4toannexb: CMP = oneline fate-hevc-bsf-mp4toannexb: REF = 1873662a3af1848c37e4eb25722c8df9 +fate-hevc-skiploopfilter: CMD = framemd5 -skip_loop_filter nokey -i $(TARGET_SAMPLES)/hevc-conformance/SAO_D_Samsung_5.bit -sws_flags bitexact +FATE_HEVC += fate-hevc-skiploopfilter + FATE_HEVC-$(call DEMDEC, HEVC, HEVC) += $(FATE_HEVC) # this sample has two stsd entries and needs to reload extradata diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak index 27d631d16..a2d5d9fe3 100644 --- a/tests/fate/libavcodec.mak +++ b/tests/fate/libavcodec.mak @@ -45,6 +45,11 @@ FATE_LIBAVCODEC-$(CONFIG_IIRFILTER) += fate-iirfilter fate-iirfilter: libavcodec/tests/iirfilter$(EXESUF) fate-iirfilter: CMD = run libavcodec/tests/iirfilter +FATE_LIBAVCODEC-$(CONFIG_MPEGVIDEO) += fate-mpeg12framerate +fate-mpeg12framerate: libavcodec/tests/mpeg12framerate$(EXESUF) +fate-mpeg12framerate: CMD = run libavcodec/tests/mpeg12framerate +fate-mpeg12framerate: REF = /dev/null + FATE_LIBAVCODEC-yes += fate-libavcodec-options fate-libavcodec-options: libavcodec/tests/options$(EXESUF) fate-libavcodec-options: CMD = run libavcodec/tests/options diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak index 591cab9b5..2ec5650c0 100644 --- a/tests/fate/libavutil.mak +++ b/tests/fate/libavutil.mak @@ -23,11 +23,6 @@ fate-cast5: libavutil/tests/cast5$(EXESUF) fate-cast5: CMD = run libavutil/tests/cast5 fate-cast5: CMP = null -FATE_LIBAVUTIL += fate-atomic -fate-atomic: libavutil/tests/atomic$(EXESUF) -fate-atomic: CMD = run libavutil/tests/atomic -fate-atomic: CMP = null - FATE_LIBAVUTIL += fate-audio_fifo fate-audio_fifo: libavutil/tests/audio_fifo$(EXESUF) fate-audio_fifo: CMD = run libavutil/tests/audio_fifo diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index cfdada7a2..64f92e948 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -6,13 +6,22 @@ FATE_MOV = fate-mov-3elist \ fate-mov-1elist-ends-last-bframe \ fate-mov-2elist-elist1-ends-bframe \ fate-mov-3elist-encrypted \ + fate-mov-invalid-elst-entry-count \ fate-mov-gpmf-remux \ + fate-mov-440hz-10ms \ + fate-mov-ibi-elst-starts-b \ + fate-mov-elst-ends-betn-b-and-i \ + fate-mov-frag-overlap \ + fate-mov-bbi-elst-starts-b \ FATE_MOV_FFPROBE = fate-mov-aac-2048-priming \ fate-mov-zombie \ fate-mov-init-nonkeyframe \ fate-mov-displaymatrix \ fate-mov-spherical-mono \ + fate-mov-guess-delay-1 \ + fate-mov-guess-delay-2 \ + fate-mov-guess-delay-3 \ FATE_SAMPLES_AVCONV += $(FATE_MOV) FATE_SAMPLES_FFPROBE += $(FATE_MOV_FFPROBE) @@ -39,6 +48,30 @@ fate-mov-1elist-ends-last-bframe: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-1e # Makes sure that we handle timestamps of packets in case of multiple edit lists with one of them ending on a B-frame correctly. fate-mov-2elist-elist1-ends-bframe: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-2elist-elist1-ends-bframe.mov +# Makes sure that if edit list ends on a B-frame but before the I-frame, then we output the B-frame but discard the I-frame. +fate-mov-elst-ends-betn-b-and-i: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/elst_ends_betn_b_and_i.mp4 + +# Makes sure that we handle edit lists and start padding correctly. +fate-mov-440hz-10ms: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/440hz-10ms.m4a + +# Makes sure that we handle invalid edit list entry count correctly. +fate-mov-invalid-elst-entry-count: CMD = framemd5 -idct simple -flags +bitexact -i $(TARGET_SAMPLES)/mov/invalid_elst_entry_count.mov + +# Makes sure that 1st key-frame is picked when, +# i) One B-frame between 2 key-frames +# ii) Edit list starts on B-frame. +# iii) Both key-frames have their DTS < edit list start +# i.e. Pts Order: I-B-I +fate-mov-ibi-elst-starts-b: CMD = framemd5 -flags +bitexact -i $(TARGET_SAMPLES)/mov/mov_ibi_elst_starts_b.mov + +# Makes sure that we handle overlapping framgments +fate-mov-frag-overlap: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/frag_overlap.mp4 + +# Makes sure that we pick the right frames according to edit list when there is no keyframe with PTS < edit list start. +# For example, when video starts on a B-frame, and edit list starts on that B-frame too. +# GOP structure : B B I in presentation order. +fate-mov-bbi-elst-starts-b: CMD = framemd5 -flags +bitexact -acodec aac_fixed -i $(TARGET_SAMPLES)/h264/twofields_packet.mp4 + fate-mov-aac-2048-priming: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_packets -print_format compact $(TARGET_SAMPLES)/mov/aac-2048-priming.mov fate-mov-zombie: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_streams -show_packets -show_frames -bitexact -print_format compact $(TARGET_SAMPLES)/mov/white_zombie_scrunch-part.mov @@ -52,3 +85,7 @@ fate-mov-spherical-mono: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries str fate-mov-gpmf-remux: CMD = md5 -i $(TARGET_SAMPLES)/mov/fake-gp-media-with-real-gpmf.mp4 -map 0 -c copy -fflags +bitexact -f mp4 fate-mov-gpmf-remux: CMP = oneline fate-mov-gpmf-remux: REF = 8f48e435ee1f6b7e173ea756141eabf3 + +fate-mov-guess-delay-1: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 +fate-mov-guess-delay-2: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_pyramid_nobsrestriction.mp4 +fate-mov-guess-delay-3: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_4bf_pyramid_nobsrestriction.mp4 diff --git a/tests/fate/mxf.mak b/tests/fate/mxf.mak index 7714b6156..dce23d522 100644 --- a/tests/fate/mxf.mak +++ b/tests/fate/mxf.mak @@ -33,9 +33,13 @@ FATE_MXF_PROBE-$(call ENCDEC2, DVVIDEO, PCM_S16LE, MXF) += fate-mxf-probe-dv25 fate-mxf-probe-dv25: SRC = $(TARGET_SAMPLES)/mxf/Avid-00005.mxf fate-mxf-probe-dv25: CMD = run $(PROBE_FORMAT_STREAMS_COMMAND) -i "$(SRC)" +FATE_MXF_REEL_NAME-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += fate-mxf-reel_name +fate-mxf-reel_name: $(TARGET_SAMPLES)/mxf/Sony-00001.mxf +fate-mxf-reel_name: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -c copy -timecode 00:00:00:00 -metadata "reel_name=test_reel" -fflags +bitexact -f mxf + FATE_MXF-$(CONFIG_MXF_DEMUXER) += $(FATE_MXF) -FATE_SAMPLES_AVCONV += $(FATE_MXF-yes) +FATE_SAMPLES_AVCONV += $(FATE_MXF-yes) $(FATE_MXF_REEL_NAME-yes) FATE_SAMPLES_FFPROBE += $(FATE_MXF_PROBE-yes) -fate-mxf: $(FATE_MXF-yes) $(FATE_MXF_PROBE-yes) +fate-mxf: $(FATE_MXF-yes) $(FATE_MXF_PROBE-yes) $(FATE_MXF_REEL_NAME-yes) diff --git a/tests/fate/opus.mak b/tests/fate/opus.mak index b13d86c13..7f289455c 100644 --- a/tests/fate/opus.mak +++ b/tests/fate/opus.mak @@ -1,26 +1,22 @@ # The samples were produced by simply rewrapping the official test vectors from -# their custom format into Matroska. -# The reference files were created with our decoder and tested against the -# libopus output with the official opus_compare tool. We cannot use libopus -# output as reference directly, because the use of different resamplers would -# require too high fuzz values, which can hide bugs. -# Before adding new tests here, always make sure they pass opus_compare. +# their custom format into Matroska. The reference decoded outputs are from the +# newest testvectors file from RFC8251 -OPUS_CELT_SAMPLES = $(addprefix testvector, 01 07 11) tron.6ch.tinypkts +OPUS_CELT_SAMPLES = $(addprefix testvector, 01 11) tron.6ch.tinypkts OPUS_HYBRID_SAMPLES = $(addprefix testvector, 05 06) OPUS_SILK_SAMPLES = $(addprefix testvector, 02 03 04) -OPUS_SAMPLES = $(addprefix testvector, 08 09 10 12) +OPUS_SAMPLES = $(addprefix testvector, 07 08 09 10 12) define FATE_OPUS_TEST FATE_OPUS += fate-opus-$(1) FATE_OPUS$(2) += fate-opus-$(1) fate-opus-$(1): CMD = ffmpeg -i $(TARGET_SAMPLES)/opus/$(1).mka -f s16le - -fate-opus-$(1): REF = $(SAMPLES)/opus/$(1).dec +fate-opus-$(1): REF = $(SAMPLES)/opus/$(1)$(2).dec endef -$(foreach N,$(OPUS_CELT_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),_CELT))) -$(foreach N,$(OPUS_HYBRID_SAMPLES),$(eval $(call FATE_OPUS_TEST,$(N),_HYBRID))) -$(foreach N,$(OPUS_SILK_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),_SILK))) +$(foreach N,$(OPUS_CELT_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N)))) +$(foreach N,$(OPUS_HYBRID_SAMPLES),$(eval $(call FATE_OPUS_TEST,$(N),_v2))) +$(foreach N,$(OPUS_SILK_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N)))) $(foreach N,$(OPUS_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),))) FATE_OPUS := $(sort $(FATE_OPUS)) @@ -28,14 +24,19 @@ FATE_OPUS := $(sort $(FATE_OPUS)) $(FATE_OPUS): CMP = stddev $(FATE_OPUS): CMP_UNIT = s16 $(FATE_OPUS): FUZZ = 3 -fate-opus-testvector02: CMP_TARGET = 191 -fate-opus-testvector03: CMP_TARGET = 139 -fate-opus-testvector04: CMP_TARGET = 119 -fate-opus-testvector05: CMP_TARGET = 108 -fate-opus-testvector06: CMP_TARGET = 106 -fate-opus-testvector08: CMP_TARGET = 6 -fate-opus-testvector10: CMP_TARGET = 38 -fate-opus-testvector12: CMP_TARGET = 160 +fate-opus-testvector01: CMP_TARGET = 0 +fate-opus-testvector02: CMP_TARGET = 191 +fate-opus-testvector03: CMP_TARGET = 139 +fate-opus-testvector04: CMP_TARGET = 119 +fate-opus-testvector05: CMP_TARGET = 108 +fate-opus-testvector06: CMP_TARGET = 106 +fate-opus-testvector07: CMP_TARGET = 0 +fate-opus-testvector08: CMP_TARGET = 6 +fate-opus-testvector09: CMP_TARGET = 0 +fate-opus-testvector10: CMP_TARGET = 38 +fate-opus-testvector11: CMP_TARGET = 0 +fate-opus-testvector12: CMP_TARGET = 160 +fate-opus-tron.6ch.tinypkts: CMP_TARGET = 0 $(FATE_OPUS_CELT): CMP = oneoff $(FATE_OPUS_CELT): FUZZ = 6 diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak index 66dfa6ba7..68b4f6f97 100644 --- a/tests/fate/screen.mak +++ b/tests/fate/screen.mak @@ -8,6 +8,15 @@ fate-dxtory: CMD = framecrc -i $(TARGET_SAMPLES)/dxtory/dxtory_mic.avi -an FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FIC) += fate-fic-avi fate-fic-avi: CMD = framecrc -i $(TARGET_SAMPLES)/fic/fic-partial-2MB.avi -an +FATE_FMVC += fate-fmvc-type1 +fate-fmvc-type1: CMD = framecrc -i $(TARGET_SAMPLES)/fmvc/6-methyl-5-hepten-2-one-CC-db_small.avi + +FATE_FMVC += fate-fmvc-type2 +fate-fmvc-type2: CMD = framecrc -i $(TARGET_SAMPLES)/fmvc/fmvcVirtualDub_small.avi + +FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FMVC) += $(FATE_FMVC) +fate-fmvc: $(FATE_FMVC) + FATE_FRAPS += fate-fraps-v0 fate-fraps-v0: CMD = framecrc -i $(TARGET_SAMPLES)/fraps/Griffin_Ragdoll01-partial.avi diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak index c863b2aaa..751873baa 100644 --- a/tests/fate/seek.mak +++ b/tests/fate/seek.mak @@ -168,7 +168,6 @@ FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16BE, AU) += au FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt -FATE_SEEK_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm FATE_SEEK_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf @@ -210,7 +209,6 @@ fate-seek-lavf-au: SRC = lavf/lavf.au fate-seek-lavf-avi: SRC = lavf/lavf.avi fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp fate-seek-lavf-dv_fmt: SRC = lavf/lavf.dv -fate-seek-lavf-ffm: SRC = lavf/lavf.ffm fate-seek-lavf-flv_fmt: SRC = lavf/lavf.flv fate-seek-lavf-gif: SRC = lavf/lavf.gif fate-seek-lavf-gxf: SRC = lavf/lavf.gxf diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak index 8c310adef..004290216 100644 --- a/tests/fate/subtitles.mak +++ b/tests/fate/subtitles.mak @@ -7,6 +7,9 @@ fate-sub-cc: CMD = fmtstdout ass -f lavfi -i "movie=$(TARGET_SAMPLES)/sub/Closed FATE_SUBTITLES_ASS-$(call ALLYES, AVDEVICE LAVFI_INDEV CCAPTION_DECODER MOVIE_FILTER MPEGTS_DEMUXER) += fate-sub-cc-realtime fate-sub-cc-realtime: CMD = fmtstdout ass -real_time 1 -f lavfi -i "movie=$(TARGET_SAMPLES)/sub/Closedcaption_rollup.m2v[out0+subcc]" +FATE_SUBTITLES_ASS-$(call ALLYES, AVDEVICE LAVFI_INDEV CCAPTION_DECODER MOVIE_FILTER MPEGTS_DEMUXER) += fate-sub-cc-scte20 +fate-sub-cc-scte20: CMD = fmtstdout ass -f lavfi -i "movie=$(TARGET_SAMPLES)/sub/scte20.ts[out0+subcc]" + FATE_SUBTITLES_ASS-$(call DEMDEC, ASS, ASS) += fate-sub-ass-to-ass-transcode fate-sub-ass-to-ass-transcode: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/1ededcbd7b.ass diff --git a/tests/fate/utvideo.mak b/tests/fate/utvideo.mak index 2cf06b36f..23224718e 100644 --- a/tests/fate/utvideo.mak +++ b/tests/fate/utvideo.mak @@ -10,6 +10,15 @@ fate-utvideo_rgba_left: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba FATE_UTVIDEO += fate-utvideo_rgba_median fate-utvideo_rgba_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba_median.avi +FATE_UTVIDEO += fate-utvideo_rgb_int_median +fate-utvideo_rgb_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgb_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_rgba_gradient +fate-utvideo_rgba_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba_gradient.avi + +FATE_UTVIDEO += fate-utvideo_rgb_int_gradient +fate-utvideo_rgb_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgb_64x48_int_gradient.avi + FATE_UTVIDEO += fate-utvideo_rgba_single_symbol fate-utvideo_rgba_single_symbol: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba_single_symbol.avi @@ -19,34 +28,64 @@ fate-utvideo_yuv420_left: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yu FATE_UTVIDEO += fate-utvideo_yuv420_median fate-utvideo_yuv420_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_median.avi +FATE_UTVIDEO += fate-utvideo_yuv420_int_median +fate-utvideo_yuv420_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_709_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv420_gradient +fate-utvideo_yuv420_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_709_64x48_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv420_int_gradient +fate-utvideo_yuv420_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_709_64x48_int_gradient.avi + FATE_UTVIDEO += fate-utvideo_yuv422_left fate-utvideo_yuv422_left: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_left.avi FATE_UTVIDEO += fate-utvideo_yuv422_median fate-utvideo_yuv422_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_median.avi +FATE_UTVIDEO += fate-utvideo_yuv422_int_median +fate-utvideo_yuv422_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_709_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv422_gradient +fate-utvideo_yuv422_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_709_64x48_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv422_int_gradient +fate-utvideo_yuv422_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_709_64x48_int_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_median +fate-utvideo_yuv444_709_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_64x48_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_int_median +fate-utvideo_yuv444_709_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_gradient +fate-utvideo_yuv444_709_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_int_gradient +fate-utvideo_yuv444_709_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_64x48_int_gradient.avi + FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, UTVIDEO) += $(FATE_UTVIDEO) fate-utvideo: $(FATE_UTVIDEO) fate-utvideoenc%: CMD = framemd5 -f image2 -c:v pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -c:v utvideo -slices 1 -sws_flags +accurate_rnd+bitexact ${OPTS} FATE_UTVIDEOENC += fate-utvideoenc_rgba_left -fate-utvideoenc_rgba_left: OPTS = -pix_fmt rgba -pred left +fate-utvideoenc_rgba_left: OPTS = -pix_fmt gbrap -pred left FATE_UTVIDEOENC += fate-utvideoenc_rgba_median -fate-utvideoenc_rgba_median: OPTS = -pix_fmt rgba -pred median +fate-utvideoenc_rgba_median: OPTS = -pix_fmt gbrap -pred median FATE_UTVIDEOENC += fate-utvideoenc_rgba_none -fate-utvideoenc_rgba_none: OPTS = -pix_fmt rgba -pred none +fate-utvideoenc_rgba_none: OPTS = -pix_fmt gbrap -pred none FATE_UTVIDEOENC += fate-utvideoenc_rgb_left -fate-utvideoenc_rgb_left: OPTS = -pix_fmt rgb24 -pred left +fate-utvideoenc_rgb_left: OPTS = -pix_fmt gbrp -pred left FATE_UTVIDEOENC += fate-utvideoenc_rgb_median -fate-utvideoenc_rgb_median: OPTS = -pix_fmt rgb24 -pred median +fate-utvideoenc_rgb_median: OPTS = -pix_fmt gbrp -pred median FATE_UTVIDEOENC += fate-utvideoenc_rgb_none -fate-utvideoenc_rgb_none: OPTS = -pix_fmt rgb24 -pred none +fate-utvideoenc_rgb_none: OPTS = -pix_fmt gbrp -pred none FATE_UTVIDEOENC += fate-utvideoenc_yuv420_left fate-utvideoenc_yuv420_left: OPTS = -pix_fmt yuv420p -pred left @@ -66,6 +105,15 @@ fate-utvideoenc_yuv422_median: OPTS = -pix_fmt yuv422p -pred median FATE_UTVIDEOENC += fate-utvideoenc_yuv422_none fate-utvideoenc_yuv422_none: OPTS = -pix_fmt yuv422p -pred none +FATE_UTVIDEOENC += fate-utvideoenc_yuv444_left +fate-utvideoenc_yuv444_left: OPTS = -pix_fmt yuv444p -pred left + +FATE_UTVIDEOENC += fate-utvideoenc_yuv444_median +fate-utvideoenc_yuv444_median: OPTS = -pix_fmt yuv444p -pred median + +FATE_UTVIDEOENC += fate-utvideoenc_yuv444_none +fate-utvideoenc_yuv444_none: OPTS = -pix_fmt yuv444p -pred none + $(FATE_UTVIDEOENC): $(VREF) FATE_AVCONV-$(call ENCMUX, UTVIDEO, AVI) += $(FATE_UTVIDEOENC) diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak index c0344550f..bbcf25d72 100644 --- a/tests/fate/vcodec.mak +++ b/tests/fate/vcodec.mak @@ -18,9 +18,9 @@ fate-vsynth%-asv1: ENCOPTS = -qscale 10 FATE_VCODEC-$(call ENCDEC, ASV2, AVI) += asv2 fate-vsynth%-asv2: ENCOPTS = -qscale 10 -FATE_VCODEC-$(call ENCDEC, CINEPAK, MOV) += cinepak -fate-vsynth%-cinepak: ENCOPTS = -c:v cinepak -frames 3 -fate-vsynth%-cinepak: FMT = mov +FATE_VCODEC-$(call ENCDEC, CINEPAK, AVI) += cinepak +fate-vsynth%-cinepak: ENCOPTS = -s sqcif -strip_number_adaptivity 1 +fate-vsynth%-cinepak: DECOPTS = -s sqcif FATE_VCODEC-$(call ENCDEC, CLJR, AVI) += cljr fate-vsynth%-cljr: ENCOPTS = -strict -1 diff --git a/tests/fate/video.mak b/tests/fate/video.mak index 930eece2c..e7817d3d1 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -69,6 +69,18 @@ fate-cavs: CMD = framecrc -i $(TARGET_SAMPLES)/cavs/cavs.mpg -an FATE_VIDEO-$(call DEMDEC, CDG, CDGRAPHICS) += fate-cdgraphics fate-cdgraphics: CMD = framecrc -i $(TARGET_SAMPLES)/cdgraphics/BrotherJohn.cdg -pix_fmt rgba -t 1 +FATE_CFHD-$(CONFIG_AVI_DEMUXER) += fate-cfhd-1 +fate-cfhd-1: CMD = framecrc -i $(TARGET_SAMPLES)/cfhd/cfhd_422.avi -pix_fmt yuv422p10le + +FATE_CFHD-$(CONFIG_AVI_DEMUXER) += fate-cfhd-2 +fate-cfhd-2: CMD = framecrc -i $(TARGET_SAMPLES)/cfhd/cfhd_444.avi -pix_fmt gbrp12le + +FATE_CFHD-$(CONFIG_MOV_DEMUXER) += fate-cfhd-3 +fate-cfhd-3: CMD = framecrc -i $(TARGET_SAMPLES)/cfhd/cfhd_odd.mov -pix_fmt yuv422p10le + +FATE_VIDEO-$(CONFIG_CFHD_DECODER) += $(FATE_CFHD-yes) +fate-cfhd: $(FATE_CFHD-yes) + FATE_VIDEO-$(call DEMDEC, AVI, CLJR) += fate-cljr fate-cljr: CMD = framecrc -i $(TARGET_SAMPLES)/cljr/testcljr-partial.avi @@ -171,6 +183,21 @@ fate-hapy: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy.mov FATE_HAP += fate-hap-chunk fate-hap-chunk: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy-12-chunks.mov +FATE_HAP += fate-hapqa-nosnappy-127x71 +fate-hapqa-nosnappy-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_NoSnappy_127x1.mov + +FATE_HAP += fate-hapqa-snappy1-127x71 +fate-hapqa-snappy1-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_1chunk_127x1.mov + +FATE_HAP += fate-hapqa-snappy16-127x71 +fate-hapqa-snappy16-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_16chunk_127x1.mov + +FATE_HAP += fate-hap-alpha-only-nosnappy-128x72 +fate-hap-alpha-only-nosnappy-128x72: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HapAlphaOnly_NoSnappy_128x72.mov -pix_fmt gray8 + +FATE_HAP += fate-hap-alpha-only-snappy-127x71 +fate-hap-alpha-only-snappy-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HapAlphaOnly_snappy1chunk_127x71.mov -pix_fmt gray8 + FATE_VIDEO-$(call DEMDEC, MOV, HAP) += $(FATE_HAP) fate-hap: $(FATE_HAP) @@ -245,6 +272,9 @@ fate-mpeg2-ticket186: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_S FATE_VIDEO-$(call DEMDEC, MPEGPS, MPEG2VIDEO) += fate-mpeg2-ticket6024 fate-mpeg2-ticket6024: CMD = framecrc -flags +bitexact -idct simple -flags +truncated -i $(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg -an +FATE_VIDEO-$(call DEMDEC, MPEGVIDEO, MPEG2VIDEO) += fate-mpeg2-ticket6677 +fate-mpeg2-ticket6677: CMD = framecrc -flags +bitexact -idct simple -vsync drop -i $(TARGET_SAMPLES)/mpeg2/sony-ct3.bs + FATE_VIDEO-$(call DEMDEC, MV, MVC1) += fate-mv-mvc1 fate-mv-mvc1: CMD = framecrc -i $(TARGET_SAMPLES)/mv/posture.mv -an -frames 25 -pix_fmt rgb555le diff --git a/tests/ffserver-regression.sh b/tests/ffserver-regression.sh deleted file mode 100755 index 9007fe37c..000000000 --- a/tests/ffserver-regression.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -target_samples=$3 -target_exec=$4 -target_path=$5 - -#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "\nFile $wd/tests/data/$_\n\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf -#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "\nFile $wd/tests/data/$_\n\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf - -. $(dirname $0)/md5.sh - -FILES=$(sed -n 's/^[^#]*.*/\1/p' $2 | grep -v html) - -rm -f tests/feed1.ffm -$target_exec ${target_path}/ffserver${PROGSUF} -f "$2" & -FFSERVER_PID=$! -echo "Waiting for feeds to startup..." -sleep 2 -( - cd tests/data || exit $? - rm -f ff-* ffserver.regression - WGET_OPTIONS="--user-agent=NSPlayer -q --proxy=off -e verbose=off -e server_response=off -T3 --tries=1" - for file in $FILES; do - if [ $(expr $file : "a-*") != 0 ]; then - wget $WGET_OPTIONS -O - http://localhost:9999/$file > ff-$file - else - wget $WGET_OPTIONS -O - http://localhost:9999/$file?date=19700101T000000Z | dd bs=1 count=100000 > ff-$file 2>/dev/null - fi - do_md5sum ff-$file >>ffserver.regression - done - wget $WGET_OPTIONS -O - 'http://localhost:9999/teststat.html?abc' > ff-stat 2>/dev/null - do_md5sum ff-stat >>ffserver.regression -) -kill $FFSERVER_PID -wait > /dev/null 2>&1 -rm -f tests/feed1.ffm -if diff -u "$1" tests/data/ffserver.regression; then - echo - echo Server regression test succeeded. - exit 0 -else - echo - echo Server regression test: Error. - exit 1 -fi diff --git a/tests/ffserver.conf b/tests/ffserver.conf deleted file mode 100644 index 3495d959e..000000000 --- a/tests/ffserver.conf +++ /dev/null @@ -1,311 +0,0 @@ -# -# This is a test configuration file. You can invoke it with -# ../ffserver -f ffserver.conf -# when in the tests directory and once the vsynth1 subdirectory -# has been populated. Then point your browser at http://whatever:9999/teststat.html -# and you can look at the streams -# - -# -# Port on which the server is listening. You must select a different -# port from your standard http web server if it is running on the same -# computer. - -HTTPPort 9999 -RTSPPort 9990 - -# Address on which the server is bound. Only useful if you have -# several network interfaces. - -HTTPBindAddress 0.0.0.0 - -# Number of simultaneous requests that can be handled. Since FFServer -# is very fast, this limit is determined mainly by your Internet -# connection speed. - -MaxClients 1000 - -MaxBandwidth 100000 - -# Access Log file (uses standard Apache log file format) -# '-' is the standard output - -CustomLog - - -################################################################## -# Definition of the live feeds. Each live feed contains one video -# and/or audio sequence coming from an ffmpeg encoder or another -# ffserver. This sequence may be encoded simultaneously with several -# codecs at several resolutions. - - - -# You must use 'ffmpeg' to send a live feed to ffserver. In this -# example, you can type: -# -# ffmpeg http://localhost:8090/feed1.ffm - -# ffserver can also do time shifting. It means that it can stream any -# previously recorded live stream. The request should contain: -# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify -# a path where the feed is stored on disk. You also specify the -# maximum size of the feed (100M bytes here). Default: -# File=/tmp/feed_name.ffm FileMaxSize=5M - -File tests/feed1.ffm -FileMaxSize 100M - -# Fire up ffmpeg pointing at this stream - -Launch ./ffmpeg -v 0 -y -f image2 -flags +bitexact -fflags +bitexact -i tests/vsynth1/%02d.pgm -flags +bitexact -fflags +bitexact - -ACL allow localhost - - -################################################################## -# Now you can define each stream which will be generated from the -# original audio and video stream. Each format has a filename (here -# 'test128.mpg'). FFServer will send this stream when answering a -# request containing this filename. - - -Feed feed1.ffm -Format avi -# -BitExact -DctFastint -IdctSimple -VideoFrameRate 10 -VideoSize 352x288 -VideoBitRate 100 -VideoGopSize 30 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - - - - -Feed feed1.ffm -Format avi -# -BitExact -DctFastint -IdctSimple -VideoFrameRate 2 -VideoSize 320x240 -VideoBitRate 40 -VideoGopSize 20 -NoAudio - -PreRoll 20 -StartSendOnKey -MaxTime 100 - - - -# -#Feed feed1.ffm -# -#VideoFrameRate 10 -#VideoSize 352x288 -#VideoBitRate 100 -#VideoGopSize 30 -#NoAudio - -#PreRoll 10 -#StartSendOnKey -#MaxTime 100 -# -# -# -# -#Feed feed1.ffm -## -#VideoFrameRate 2 -#VideoSize 320x240 -#VideoBitRate 40 -#VideoGopSize 20 -#NoAudio -# -#PreRoll 20 -#StartSendOnKey -#MaxTime 100 -# -# -# - -Feed feed1.ffm -# -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoFrameRate 10 -VideoSize 352x288 -VideoBitRate 100 -VideoGopSize 30 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - - - - -Feed feed1.ffm -Format asf -# -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoFrameRate 10 -VideoSize 320x240 -VideoBitRate 100 -VideoGopSize 30 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - -AVOptionVideo flags +global_header - -Metadata title "Test data stream" - - - - -Feed feed1.ffm -Format asf -# -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoFrameRate 2 -VideoSize 320x240 -VideoBitRate 40 -VideoGopSize 20 -NoAudio - -PreRoll 20 -StartSendOnKey -MaxTime 100 - -AVOptionVideo flags +global_header - -Metadata title "Test data stream" - - - - - -Feed feed1.ffm -Format rm - -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoBitRate 100 -VideoFrameRate 10 -VideoGopSize 30 -VideoSize 320x240 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - - - - - -Feed feed1.ffm -Format rm - -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoBitRate 40 -VideoFrameRate 2 -VideoGopSize 20 -VideoSize 320x240 -NoAudio - -PreRoll 20 -StartSendOnKey -MaxTime 100 - - - - - - -Feed feed1.ffm -Format jpeg -Strict -1 - -BitExact -DctFastint -IdctSimple -VideoFrameRate 1 -VideoSize 352x288 -NoAudio - -PreRoll 2 - - - - - -Feed feed1.ffm -Format jpeg -Strict -1 - -BitExact -DctFastint -IdctSimple -VideoFrameRate 1 -VideoSize 160x128 -NoAudio - -PreRoll 2 - - - - - -Feed feed1.ffm -Format mpjpeg -Strict -1 - -BitExact -DctFastint -IdctSimple -VideoFrameRate 1 -VideoSize 320x240 -NoAudio -StartSendOnKey - -PreRoll 1 -MaxTime 100 - - - - -################################################################## -# Special stream : server status - - - -Format status - - - diff --git a/tests/ffserver.regression.ref b/tests/ffserver.regression.ref deleted file mode 100644 index 398c28515..000000000 --- a/tests/ffserver.regression.ref +++ /dev/null @@ -1,11 +0,0 @@ -0c9639f09decbc54c9f091dcf1ca0e8f *ff-test_h.avi -e28ba75853caf975e06d92955c9f7f73 *ff-test_l.avi -a767dbdf5d1bded3450279f812f97b37 *ff-test.swf -dc16f607e13328a832e73801cd21ec98 *ff-test_h.asf -69337d6c8cd7ac7e626338decdbf41d3 *ff-test_l.asf -06f5a6a4c5d1c6735f4d0068e825c91f *ff-test_h.rm -1f57580f02f0317407b3b82a3d5e093f *ff-test_l.rm -4c887dfc1dd0f6ea1a3a2be6dd32e495 *ff-test.jpg -1d04b73b04aad27793cc762d5afabac1 *ff-test_small.jpg -bc36c40ee34ebee6ffe50f3094aab733 *ff-test.mjpg -fd038af80560e15271ce42651093ee43 *ff-stat diff --git a/tests/ref/fate/api-mjpeg-codec-param b/tests/ref/fate/api-mjpeg-codec-param index 02f656df2..178b7c73c 100644 --- a/tests/ref/fate/api-mjpeg-codec-param +++ b/tests/ref/fate/api-mjpeg-codec-param @@ -3,7 +3,6 @@ stream=0, decode=0 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -18,7 +17,6 @@ stream=0, decode=0 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -38,18 +36,12 @@ stream=0, decode=0 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -64,7 +56,6 @@ stream=0, decode=0 aspect=180/180 sar=180/180 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -75,27 +66,17 @@ stream=0, decode=0 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 @@ -107,7 +88,6 @@ stream=0, decode=0 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -120,7 +100,6 @@ stream=0, decode=0 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 @@ -163,7 +142,6 @@ stream=0, decode=1 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -178,7 +156,6 @@ stream=0, decode=1 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -198,18 +175,12 @@ stream=0, decode=1 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -224,7 +195,6 @@ stream=0, decode=1 aspect=180/180 sar=180/180 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -235,27 +205,17 @@ stream=0, decode=1 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 @@ -267,7 +227,6 @@ stream=0, decode=1 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -280,7 +239,6 @@ stream=0, decode=1 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 diff --git a/tests/ref/fate/api-png-codec-param b/tests/ref/fate/api-png-codec-param index de86f1b25..c6ea7c629 100644 --- a/tests/ref/fate/api-png-codec-param +++ b/tests/ref/fate/api-png-codec-param @@ -3,7 +3,6 @@ stream=0, decode=0 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -18,7 +17,6 @@ stream=0, decode=0 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -38,18 +36,12 @@ stream=0, decode=0 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -64,7 +56,6 @@ stream=0, decode=0 aspect=2835/2835 sar=2835/2835 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -75,27 +66,17 @@ stream=0, decode=0 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 @@ -107,7 +88,6 @@ stream=0, decode=0 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -120,7 +100,6 @@ stream=0, decode=0 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 @@ -163,7 +142,6 @@ stream=0, decode=1 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -178,7 +156,6 @@ stream=0, decode=1 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -198,18 +175,12 @@ stream=0, decode=1 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -224,7 +195,6 @@ stream=0, decode=1 aspect=2835/2835 sar=2835/2835 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -235,27 +205,17 @@ stream=0, decode=1 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 @@ -267,7 +227,6 @@ stream=0, decode=1 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -280,7 +239,6 @@ stream=0, decode=1 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 diff --git a/tests/ref/fate/cbs-h264-AUD_MW_E b/tests/ref/fate/cbs-h264-AUD_MW_E new file mode 100644 index 000000000..f20479241 --- /dev/null +++ b/tests/ref/fate/cbs-h264-AUD_MW_E @@ -0,0 +1 @@ +9b8884667eda0b9853bec631458686ce diff --git a/tests/ref/fate/cbs-h264-BASQP1_Sony_C b/tests/ref/fate/cbs-h264-BASQP1_Sony_C new file mode 100644 index 000000000..c2185c770 --- /dev/null +++ b/tests/ref/fate/cbs-h264-BASQP1_Sony_C @@ -0,0 +1 @@ +00c52ae60bf9a41ae1145fbf5fea9838 diff --git a/tests/ref/fate/cbs-h264-CABACI3_Sony_B b/tests/ref/fate/cbs-h264-CABACI3_Sony_B new file mode 100644 index 000000000..59aeb7215 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CABACI3_Sony_B @@ -0,0 +1 @@ +2d94c80b858aec880530bad47afe3668 diff --git a/tests/ref/fate/cbs-h264-CVBS3_Sony_C b/tests/ref/fate/cbs-h264-CVBS3_Sony_C new file mode 100644 index 000000000..55f5e0b50 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVBS3_Sony_C @@ -0,0 +1 @@ +59ff1df9b25e80277cad4ad99e634df6 diff --git a/tests/ref/fate/cbs-h264-CVFC1_Sony_C b/tests/ref/fate/cbs-h264-CVFC1_Sony_C new file mode 100644 index 000000000..98004cf63 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVFC1_Sony_C @@ -0,0 +1 @@ +669f4f3d3ae35fa5a6f5c94e48776dcf diff --git a/tests/ref/fate/cbs-h264-CVMANL1_TOSHIBA_B b/tests/ref/fate/cbs-h264-CVMANL1_TOSHIBA_B new file mode 100644 index 000000000..14aa45300 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVMANL1_TOSHIBA_B @@ -0,0 +1 @@ +0c1d9694df747cc4697caf866bd3051a diff --git a/tests/ref/fate/cbs-h264-CVNLFI1_Sony_C b/tests/ref/fate/cbs-h264-CVNLFI1_Sony_C new file mode 100644 index 000000000..d5f5ad193 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVNLFI1_Sony_C @@ -0,0 +1 @@ +7817d89bd749bc617a225978958a3af0 diff --git a/tests/ref/fate/cbs-h264-CVSE2_Sony_B b/tests/ref/fate/cbs-h264-CVSE2_Sony_B new file mode 100644 index 000000000..7845723ed --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVSE2_Sony_B @@ -0,0 +1 @@ +ca8bdba497bd2f3b97c50d59692eb537 diff --git a/tests/ref/fate/cbs-h264-CVWP1_TOSHIBA_E b/tests/ref/fate/cbs-h264-CVWP1_TOSHIBA_E new file mode 100644 index 000000000..4cb9c475f --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVWP1_TOSHIBA_E @@ -0,0 +1 @@ +01290611165b8d8ccba8468f3dae4c4d diff --git a/tests/ref/fate/cbs-h264-FM1_BT_B b/tests/ref/fate/cbs-h264-FM1_BT_B new file mode 100644 index 000000000..862de950d --- /dev/null +++ b/tests/ref/fate/cbs-h264-FM1_BT_B @@ -0,0 +1 @@ +f7d5474ec576eea3f70d83a26a641a60 diff --git a/tests/ref/fate/cbs-h264-MR1_BT_A b/tests/ref/fate/cbs-h264-MR1_BT_A new file mode 100644 index 000000000..0532652e6 --- /dev/null +++ b/tests/ref/fate/cbs-h264-MR1_BT_A @@ -0,0 +1 @@ +699d37e66764ddb3b4265c299ca77dcd diff --git a/tests/ref/fate/cbs-h264-SVA_Base_B b/tests/ref/fate/cbs-h264-SVA_Base_B new file mode 100644 index 000000000..a591b811b --- /dev/null +++ b/tests/ref/fate/cbs-h264-SVA_Base_B @@ -0,0 +1 @@ +443e55dd5f63dccf9a62acbb48451b08 diff --git a/tests/ref/fate/cbs-h264-Sharp_MP_PAFF_1r2 b/tests/ref/fate/cbs-h264-Sharp_MP_PAFF_1r2 new file mode 100644 index 000000000..cc7d63931 --- /dev/null +++ b/tests/ref/fate/cbs-h264-Sharp_MP_PAFF_1r2 @@ -0,0 +1 @@ +fd01840ed6b086c3118b7c53c86d01f5 diff --git a/tests/ref/fate/cbs-h264-sp1_bt_a b/tests/ref/fate/cbs-h264-sp1_bt_a new file mode 100644 index 000000000..388c53aa5 --- /dev/null +++ b/tests/ref/fate/cbs-h264-sp1_bt_a @@ -0,0 +1 @@ +8405c5583d31d7015ed401b34b4ec93c diff --git a/tests/ref/fate/cbs-hevc-CAINIT_E_SHARP_3 b/tests/ref/fate/cbs-hevc-CAINIT_E_SHARP_3 new file mode 100644 index 000000000..53af86aaa --- /dev/null +++ b/tests/ref/fate/cbs-hevc-CAINIT_E_SHARP_3 @@ -0,0 +1 @@ +44d1c0b80828af779d942cc20dde4ea4 diff --git a/tests/ref/fate/cbs-hevc-CAINIT_H_SHARP_3 b/tests/ref/fate/cbs-hevc-CAINIT_H_SHARP_3 new file mode 100644 index 000000000..5e127d789 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-CAINIT_H_SHARP_3 @@ -0,0 +1 @@ +ae9311dfcaf65bb8de9c4fcf23ce0871 diff --git a/tests/ref/fate/cbs-hevc-CONFWIN_A_Sony_1 b/tests/ref/fate/cbs-hevc-CONFWIN_A_Sony_1 new file mode 100644 index 000000000..00445155d --- /dev/null +++ b/tests/ref/fate/cbs-hevc-CONFWIN_A_Sony_1 @@ -0,0 +1 @@ +dce8104b2addbdd601eb280a88e18583 diff --git a/tests/ref/fate/cbs-hevc-HRD_A_Fujitsu_2 b/tests/ref/fate/cbs-hevc-HRD_A_Fujitsu_2 new file mode 100644 index 000000000..b9c90ae3c --- /dev/null +++ b/tests/ref/fate/cbs-hevc-HRD_A_Fujitsu_2 @@ -0,0 +1 @@ +716a90051f028c90daeb86b3825af36d diff --git a/tests/ref/fate/cbs-hevc-LTRPSPS_A_Qualcomm_1 b/tests/ref/fate/cbs-hevc-LTRPSPS_A_Qualcomm_1 new file mode 100644 index 000000000..21dfa5763 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-LTRPSPS_A_Qualcomm_1 @@ -0,0 +1 @@ +11b599202a4d25693123bea8bb003e54 diff --git a/tests/ref/fate/cbs-hevc-NUT_A_ericsson_5 b/tests/ref/fate/cbs-hevc-NUT_A_ericsson_5 new file mode 100644 index 000000000..32e58affe --- /dev/null +++ b/tests/ref/fate/cbs-hevc-NUT_A_ericsson_5 @@ -0,0 +1 @@ +25cf94dfa2e0334eeedbfa9a8ed1c4b2 diff --git a/tests/ref/fate/cbs-hevc-PICSIZE_A_Bossen_1 b/tests/ref/fate/cbs-hevc-PICSIZE_A_Bossen_1 new file mode 100644 index 000000000..cc1800492 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-PICSIZE_A_Bossen_1 @@ -0,0 +1 @@ +e87fbd90c297d401738db928e3e04dd4 diff --git a/tests/ref/fate/cbs-hevc-PICSIZE_B_Bossen_1 b/tests/ref/fate/cbs-hevc-PICSIZE_B_Bossen_1 new file mode 100644 index 000000000..5495cec6c --- /dev/null +++ b/tests/ref/fate/cbs-hevc-PICSIZE_B_Bossen_1 @@ -0,0 +1 @@ +4993d49d6f2f532dfc683a9d26c1e313 diff --git a/tests/ref/fate/cbs-hevc-RPLM_A_qualcomm_4 b/tests/ref/fate/cbs-hevc-RPLM_A_qualcomm_4 new file mode 100644 index 000000000..c68d615cb --- /dev/null +++ b/tests/ref/fate/cbs-hevc-RPLM_A_qualcomm_4 @@ -0,0 +1 @@ +f5d2633eefcd95e189faf4302d270457 diff --git a/tests/ref/fate/cbs-hevc-RPS_A_docomo_4 b/tests/ref/fate/cbs-hevc-RPS_A_docomo_4 new file mode 100644 index 000000000..772d16a19 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-RPS_A_docomo_4 @@ -0,0 +1 @@ +97bd4fefd8cd95584f586027e244f283 diff --git a/tests/ref/fate/cbs-hevc-RPS_E_qualcomm_5 b/tests/ref/fate/cbs-hevc-RPS_E_qualcomm_5 new file mode 100644 index 000000000..faef7da0d --- /dev/null +++ b/tests/ref/fate/cbs-hevc-RPS_E_qualcomm_5 @@ -0,0 +1 @@ +b2528ef681729176ccb38a77be93a0de diff --git a/tests/ref/fate/cbs-hevc-SLIST_A_Sony_4 b/tests/ref/fate/cbs-hevc-SLIST_A_Sony_4 new file mode 100644 index 000000000..23b2e324d --- /dev/null +++ b/tests/ref/fate/cbs-hevc-SLIST_A_Sony_4 @@ -0,0 +1 @@ +72cf53bbc967c9679e21a6d3203edb07 diff --git a/tests/ref/fate/cbs-hevc-SLIST_D_Sony_9 b/tests/ref/fate/cbs-hevc-SLIST_D_Sony_9 new file mode 100644 index 000000000..4cea86dba --- /dev/null +++ b/tests/ref/fate/cbs-hevc-SLIST_D_Sony_9 @@ -0,0 +1 @@ +59a22d715e30748492da5e0b9d421909 diff --git a/tests/ref/fate/cbs-hevc-STRUCT_A_Samsung_5 b/tests/ref/fate/cbs-hevc-STRUCT_A_Samsung_5 new file mode 100644 index 000000000..6a4508b0c --- /dev/null +++ b/tests/ref/fate/cbs-hevc-STRUCT_A_Samsung_5 @@ -0,0 +1 @@ +647eb851b935fd3bc6a98ce5ce45dbc7 diff --git a/tests/ref/fate/cbs-hevc-TILES_B_Cisco_1 b/tests/ref/fate/cbs-hevc-TILES_B_Cisco_1 new file mode 100644 index 000000000..d767e26d6 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-TILES_B_Cisco_1 @@ -0,0 +1 @@ +85a114def19cefbd0fb0daf8370d711c diff --git a/tests/ref/fate/cbs-hevc-WPP_A_ericsson_MAIN_2 b/tests/ref/fate/cbs-hevc-WPP_A_ericsson_MAIN_2 new file mode 100644 index 000000000..fe6928fc8 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-WPP_A_ericsson_MAIN_2 @@ -0,0 +1 @@ +de7d440b556eea827953e6d12aeb4023 diff --git a/tests/ref/fate/cbs-hevc-WPP_F_ericsson_MAIN_2 b/tests/ref/fate/cbs-hevc-WPP_F_ericsson_MAIN_2 new file mode 100644 index 000000000..08aee566f --- /dev/null +++ b/tests/ref/fate/cbs-hevc-WPP_F_ericsson_MAIN_2 @@ -0,0 +1 @@ +f197136f1fb3242c3422a48470dd7d35 diff --git a/tests/ref/fate/cbs-hevc-WP_A_Toshiba_3 b/tests/ref/fate/cbs-hevc-WP_A_Toshiba_3 new file mode 100644 index 000000000..b868c438f --- /dev/null +++ b/tests/ref/fate/cbs-hevc-WP_A_Toshiba_3 @@ -0,0 +1 @@ +158312a1a35ef4b20cb4aeee48549c03 diff --git a/tests/ref/fate/cbs-hevc-ipcm_E_NEC_2 b/tests/ref/fate/cbs-hevc-ipcm_E_NEC_2 new file mode 100644 index 000000000..cc68b6fb4 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-ipcm_E_NEC_2 @@ -0,0 +1 @@ +2e1f9c95364cfac2aa6e6ee3a52c43c4 diff --git a/tests/ref/fate/cbs-mpeg2-hhi_burst_422_short b/tests/ref/fate/cbs-mpeg2-hhi_burst_422_short new file mode 100644 index 000000000..c319fba7b --- /dev/null +++ b/tests/ref/fate/cbs-mpeg2-hhi_burst_422_short @@ -0,0 +1 @@ +e0c2fdd9baeba0c5ba5839a8cd7a72d3 diff --git a/tests/ref/fate/cbs-mpeg2-sony-ct3 b/tests/ref/fate/cbs-mpeg2-sony-ct3 new file mode 100644 index 000000000..b5b4b12f0 --- /dev/null +++ b/tests/ref/fate/cbs-mpeg2-sony-ct3 @@ -0,0 +1 @@ +b1e15a09cfffbad801810af0928736ab diff --git a/tests/ref/fate/cbs-mpeg2-tcela-6 b/tests/ref/fate/cbs-mpeg2-tcela-6 new file mode 100644 index 000000000..530369d67 --- /dev/null +++ b/tests/ref/fate/cbs-mpeg2-tcela-6 @@ -0,0 +1 @@ +771b6756a63793e05b74e645794908a2 diff --git a/tests/ref/fate/cfhd-1 b/tests/ref/fate/cfhd-1 new file mode 100644 index 000000000..0280d66df --- /dev/null +++ b/tests/ref/fate/cfhd-1 @@ -0,0 +1,15 @@ +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 0/1 +0, 0, 0, 1, 1382400, 0xa3e49817 +0, 1, 1, 1, 1382400, 0x544fdfac +0, 2, 2, 1, 1382400, 0x84964e11 +0, 3, 3, 1, 1382400, 0xc608c8d1 +0, 4, 4, 1, 1382400, 0xf2f1404f +0, 5, 5, 1, 1382400, 0x5a3100ba +0, 6, 6, 1, 1382400, 0x3727baa9 +0, 7, 7, 1, 1382400, 0x894f07db +0, 8, 8, 1, 1382400, 0x3ef27d46 +0, 9, 9, 1, 1382400, 0x1f90880d diff --git a/tests/ref/fate/cfhd-2 b/tests/ref/fate/cfhd-2 new file mode 100644 index 000000000..77db54c26 --- /dev/null +++ b/tests/ref/fate/cfhd-2 @@ -0,0 +1,15 @@ +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 0/1 +0, 0, 0, 1, 2073600, 0x53fab433 +0, 1, 1, 1, 2073600, 0x0d2b3f64 +0, 2, 2, 1, 2073600, 0x857d1d48 +0, 3, 3, 1, 2073600, 0xe1a7df32 +0, 4, 4, 1, 2073600, 0x615861c1 +0, 5, 5, 1, 2073600, 0xf6cdb0a9 +0, 6, 6, 1, 2073600, 0x55dd9f16 +0, 7, 7, 1, 2073600, 0x7c126a32 +0, 8, 8, 1, 2073600, 0x53fdd4c5 +0, 9, 9, 1, 2073600, 0x6062a4b3 diff --git a/tests/ref/fate/cfhd-3 b/tests/ref/fate/cfhd-3 new file mode 100644 index 000000000..60e13c64a --- /dev/null +++ b/tests/ref/fate/cfhd-3 @@ -0,0 +1,15 @@ +#tb 0: 1000/14587 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 496x241 +#sar 0: 0/1 +0, 0, 0, 1, 478144, 0x6ed01dcd +0, 1, 1, 1, 478144, 0x6ed01dcd +0, 2, 2, 1, 478144, 0x6ed01dcd +0, 3, 3, 1, 478144, 0xb1b4a74b +0, 4, 4, 1, 478144, 0x94c345c3 +0, 5, 5, 1, 478144, 0x05e0388d +0, 6, 6, 1, 478144, 0xe747476a +0, 7, 7, 1, 478144, 0x8c1561f1 +0, 8, 8, 1, 478144, 0x8c1561f1 +0, 9, 9, 1, 478144, 0x8c1561f1 diff --git a/tests/ref/fate/copy-trac2211-avi b/tests/ref/fate/copy-trac2211-avi index 007349e57..06d81e537 100644 --- a/tests/ref/fate/copy-trac2211-avi +++ b/tests/ref/fate/copy-trac2211-avi @@ -1,5 +1,5 @@ -6f6b211cbc8de9871e8e09e64048e2f9 *tests/data/fate/copy-trac2211-avi.avi -1777924 tests/data/fate/copy-trac2211-avi.avi +0920978f3f8196413c43f0033b55a5b6 *tests/data/fate/copy-trac2211-avi.avi +1777956 tests/data/fate/copy-trac2211-avi.avi #tb 0: 1/14 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/copy-trac4914 b/tests/ref/fate/copy-trac4914 index e0864a003..a8f287faf 100644 --- a/tests/ref/fate/copy-trac4914 +++ b/tests/ref/fate/copy-trac4914 @@ -1,4 +1,4 @@ -d51f6bcc96885a2ce8517ae8c774f610 *tests/data/fate/copy-trac4914.mxf +05fdc4a6e28abb2c26e96224682d2684 *tests/data/fate/copy-trac4914.mxf 560697 tests/data/fate/copy-trac4914.mxf #tb 0: 1001/30000 #media_type 0: video diff --git a/tests/ref/fate/ffmpeg-attached_pics b/tests/ref/fate/ffmpeg-attached_pics new file mode 100644 index 000000000..ee2f20638 --- /dev/null +++ b/tests/ref/fate/ffmpeg-attached_pics @@ -0,0 +1,140 @@ +#tb 0: 1/90000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 200x200 +#sar 0: 2834/2834 +#tb 1: 1/44100 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 44100 +#channel_layout 1: 3 +#channel_layout_name 1: stereo +0, 0, 0, 0, 120000, 0x748cc771 +1, 0, 0, 4096, 16384, 0x00000000 +1, 4096, 4096, 4096, 16384, 0x29cd639d +1, 8192, 8192, 4096, 16384, 0xd52066e5 +1, 12288, 12288, 4096, 16384, 0x0c933408 +1, 16384, 16384, 4096, 16384, 0xb3b97675 +1, 20480, 20480, 4096, 16384, 0x1cb4a26b +1, 24576, 24576, 4096, 16384, 0x6bf693b9 +1, 28672, 28672, 4096, 16384, 0x12896c95 +1, 32768, 32768, 4096, 16384, 0x48b7167a +1, 36864, 36864, 4096, 16384, 0x5a9c06ad +1, 40960, 40960, 4096, 16384, 0x42fa8e65 +1, 45056, 45056, 4096, 16384, 0x175e6a61 +1, 49152, 49152, 4096, 16384, 0x3cd0e606 +1, 53248, 53248, 4096, 16384, 0x5ceff67d +1, 57344, 57344, 4096, 16384, 0xa24ba733 +1, 61440, 61440, 4096, 16384, 0xafe61a2d +1, 65536, 65536, 4096, 16384, 0xef8355f1 +1, 69632, 69632, 4096, 16384, 0x8e53cb7c +1, 73728, 73728, 4096, 16384, 0x461bb940 +1, 77824, 77824, 4096, 16384, 0x96bb6ebd +1, 81920, 81920, 4096, 16384, 0xb99977dc +1, 86016, 86016, 4096, 16384, 0xa6b6a178 +1, 90112, 90112, 4096, 16384, 0x7bdc3e50 +1, 94208, 94208, 4096, 16384, 0x44cda519 +1, 98304, 98304, 4096, 16384, 0xbdfd2e72 +1, 102400, 102400, 4096, 16384, 0x5c09dc3c +1, 106496, 106496, 4096, 16384, 0xe5aabb75 +1, 110592, 110592, 4096, 16384, 0x5db83fb2 +1, 114688, 114688, 4096, 16384, 0x69a6e3c0 +1, 118784, 118784, 4096, 16384, 0x0c09a90d +1, 122880, 122880, 4096, 16384, 0x978d2b50 +1, 126976, 126976, 4096, 16384, 0x9707fbaa +1, 131072, 131072, 4096, 16384, 0x8003f93b +1, 135168, 135168, 4096, 16384, 0xaa12ab0c +1, 139264, 139264, 4096, 16384, 0x49980501 +1, 143360, 143360, 4096, 16384, 0xdcb891db +1, 147456, 147456, 4096, 16384, 0x52b76938 +1, 151552, 151552, 4096, 16384, 0x7cb55457 +1, 155648, 155648, 4096, 16384, 0x6b08b7d2 +1, 159744, 159744, 4096, 16384, 0xb56bb312 +1, 163840, 163840, 4096, 16384, 0xcbf9d3e0 +1, 167936, 167936, 4096, 16384, 0xe8958c07 +1, 172032, 172032, 4096, 16384, 0x054ac021 +1, 176128, 176128, 4096, 16384, 0x36811603 +1, 180224, 180224, 4096, 16384, 0x3354f6e1 +1, 184320, 184320, 4096, 16384, 0xa6c11686 +1, 188416, 188416, 4096, 16384, 0xed353877 +1, 192512, 192512, 4096, 16384, 0xef21373e +1, 196608, 196608, 4096, 16384, 0x31c806d9 +1, 200704, 200704, 4096, 16384, 0x3c1c79d4 +1, 204800, 204800, 4096, 16384, 0x1b7b3d9a +1, 208896, 208896, 4096, 16384, 0x08977239 +1, 212992, 212992, 4096, 16384, 0x07f9d169 +1, 217088, 217088, 4096, 16384, 0xa66ae19a +1, 221184, 221184, 4096, 16384, 0x42f51169 +1, 225280, 225280, 4096, 16384, 0x98ff59b6 +1, 229376, 229376, 4096, 16384, 0x855216b9 +1, 233472, 233472, 4096, 16384, 0x0986573d +1, 237568, 237568, 4096, 16384, 0x060aeffe +1, 241664, 241664, 4096, 16384, 0x391c19bc +1, 245760, 245760, 4096, 16384, 0x9939c472 +1, 249856, 249856, 4096, 16384, 0x4e0d31c5 +1, 253952, 253952, 4096, 16384, 0xed2678a6 +1, 258048, 258048, 4096, 16384, 0xfd899fc3 +1, 262144, 262144, 4096, 16384, 0x35cf5263 +1, 266240, 266240, 4096, 16384, 0xa2e35dad +1, 270336, 270336, 4096, 16384, 0xf9ed08a0 +1, 274432, 274432, 4096, 16384, 0x022d9356 +1, 278528, 278528, 4096, 16384, 0x508042f7 +1, 282624, 282624, 4096, 16384, 0xe2e7e70b +1, 286720, 286720, 4096, 16384, 0x30812bfd +1, 290816, 290816, 4096, 16384, 0x5590ea7d +1, 294912, 294912, 4096, 16384, 0xebaa4fc4 +1, 299008, 299008, 4096, 16384, 0x731cee53 +1, 303104, 303104, 4096, 16384, 0x1127b480 +1, 307200, 307200, 4096, 16384, 0x0809f7c8 +1, 311296, 311296, 4096, 16384, 0xc0d4256f +1, 315392, 315392, 4096, 16384, 0xe868795c +1, 319488, 319488, 4096, 16384, 0x801a77d1 +1, 323584, 323584, 4096, 16384, 0x1d44bed5 +1, 327680, 327680, 4096, 16384, 0x7619f16b +1, 331776, 331776, 4096, 16384, 0x301064b6 +1, 335872, 335872, 4096, 16384, 0x42f3e0fb +1, 339968, 339968, 4096, 16384, 0xfe186dc6 +1, 344064, 344064, 4096, 16384, 0x1a9bbbab +1, 348160, 348160, 4096, 16384, 0x3c4e00a8 +1, 352256, 352256, 4096, 16384, 0x3101c84e +1, 356352, 356352, 4096, 16384, 0x11a6c764 +1, 360448, 360448, 4096, 16384, 0xb75e82a1 +1, 364544, 364544, 4096, 16384, 0x81e3b3dd +1, 368640, 368640, 4096, 16384, 0x2656fc8e +1, 372736, 372736, 4096, 16384, 0x6c655f40 +1, 376832, 376832, 4096, 16384, 0xba0432f9 +1, 380928, 380928, 4096, 16384, 0x7028ee57 +1, 385024, 385024, 4096, 16384, 0x16baf6ed +1, 389120, 389120, 4096, 16384, 0x863bcff5 +1, 393216, 393216, 4096, 16384, 0x4dbce87e +1, 397312, 397312, 4096, 16384, 0x825e268c +1, 401408, 401408, 4096, 16384, 0xfe269f0a +1, 405504, 405504, 4096, 16384, 0x47b9c0ef +1, 409600, 409600, 4096, 16384, 0xbbe55aac +1, 413696, 413696, 4096, 16384, 0xeb0674a7 +1, 417792, 417792, 4096, 16384, 0x01afba1b +1, 421888, 421888, 4096, 16384, 0x5ec18306 +1, 425984, 425984, 4096, 16384, 0x6d0b844f +1, 430080, 430080, 4096, 16384, 0x6cd1bea2 +1, 434176, 434176, 4096, 16384, 0x97e47cbb +1, 438272, 438272, 4096, 16384, 0xbb6bf554 +1, 442368, 442368, 4096, 16384, 0x33ea7961 +1, 446464, 446464, 4096, 16384, 0x83ce2f2a +1, 450560, 450560, 4096, 16384, 0x3bed9e0d +1, 454656, 454656, 4096, 16384, 0xd3a9570a +1, 458752, 458752, 4096, 16384, 0x4d5e1aca +1, 462848, 462848, 4096, 16384, 0x874a9b11 +1, 466944, 466944, 4096, 16384, 0xe51061d8 +1, 471040, 471040, 4096, 16384, 0x3582fac4 +1, 475136, 475136, 4096, 16384, 0x35df558e +1, 479232, 479232, 4096, 16384, 0xe2485fed +1, 483328, 483328, 4096, 16384, 0x31f9c6a7 +1, 487424, 487424, 4096, 16384, 0x0a82b244 +1, 491520, 491520, 4096, 16384, 0xfbb428f4 +1, 495616, 495616, 4096, 16384, 0x57b90bb6 +1, 499712, 499712, 4096, 16384, 0x5c6daa1a +1, 503808, 503808, 4096, 16384, 0xe02ac113 +1, 507904, 507904, 4096, 16384, 0x47ed59b6 +1, 512000, 512000, 4096, 16384, 0x220e4bd3 +1, 516096, 516096, 4096, 16384, 0x65de48b1 +1, 520192, 520192, 4085, 16340, 0x326fa751 diff --git a/tests/ref/fate/ffmpeg-filter_complex_audio b/tests/ref/fate/ffmpeg-filter_complex_audio new file mode 100644 index 000000000..c42467506 --- /dev/null +++ b/tests/ref/fate/ffmpeg-filter_complex_audio @@ -0,0 +1,10 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: ac3 +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, -256, -256, 1536, 416, 0x3001fb2d +0, 1280, 1280, 1536, 418, 0xba72fc16 +0, 2816, 2816, 1536, 418, 0xba72fc16 +0, 4352, 4352, 1536, 418, 0xba72fc16 diff --git a/tests/ref/fate/fifo-muxer-tst b/tests/ref/fate/fifo-muxer-tst index ca7e29486..e1139ee0a 100644 --- a/tests/ref/fate/fifo-muxer-tst +++ b/tests/ref/fate/fifo-muxer-tst @@ -2,7 +2,6 @@ flush count: 1 pts seen nr: 15 pts seen: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 nonfail test: ok -write header error test: ok recovery test: ok flush count: 1 pts seen nr: 15 diff --git a/tests/ref/fate/filter-framerate-12bit-down b/tests/ref/fate/filter-framerate-12bit-down new file mode 100644 index 000000000..49dcb1e5f --- /dev/null +++ b/tests/ref/fate/filter-framerate-12bit-down @@ -0,0 +1,55 @@ +#tb 0: 1/50 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 307200, 0xb49cf016 +0, 1, 1, 1, 307200, 0xc3be6971 +0, 2, 2, 1, 307200, 0x4d458da1 +0, 3, 3, 1, 307200, 0xb49ed940 +0, 4, 4, 1, 307200, 0x1577849f +0, 5, 5, 1, 307200, 0xaf71e7fc +0, 6, 6, 1, 307200, 0x1290a487 +0, 7, 7, 1, 307200, 0xaf0cf5ee +0, 8, 8, 1, 307200, 0x6ffb3abb +0, 9, 9, 1, 307200, 0x9e65597e +0, 10, 10, 1, 307200, 0x9f84df5d +0, 11, 11, 1, 307200, 0xf60b8c87 +0, 12, 12, 1, 307200, 0xe2eac3a7 +0, 13, 13, 1, 307200, 0x2c4ac771 +0, 14, 14, 1, 307200, 0xf4d9003d +0, 15, 15, 1, 307200, 0xab2162fc +0, 16, 16, 1, 307200, 0xdc90848a +0, 17, 17, 1, 307200, 0x29f79f4b +0, 18, 18, 1, 307200, 0x45b1e01b +0, 19, 19, 1, 307200, 0x43baddc2 +0, 20, 20, 1, 307200, 0xf2b12fe5 +0, 21, 21, 1, 307200, 0x1de67e13 +0, 22, 22, 1, 307200, 0xfc1f7774 +0, 23, 23, 1, 307200, 0x5552e7f2 +0, 24, 24, 1, 307200, 0xb1d60366 +0, 25, 25, 1, 307200, 0x4693ab03 +0, 26, 26, 1, 307200, 0x7295ef7a +0, 27, 27, 1, 307200, 0xf442a5df +0, 28, 28, 1, 307200, 0x01e0dbb8 +0, 29, 29, 1, 307200, 0xf10c3549 +0, 30, 30, 1, 307200, 0x8a512668 +0, 31, 31, 1, 307200, 0x69e7b43e +0, 32, 32, 1, 307200, 0x6c5343ca +0, 33, 33, 1, 307200, 0xf323456c +0, 34, 34, 1, 307200, 0xeead5632 +0, 35, 35, 1, 307200, 0x4e24d659 +0, 36, 36, 1, 307200, 0x7a25b546 +0, 37, 37, 1, 307200, 0x9b7e8e8f +0, 38, 38, 1, 307200, 0x9d059d4c +0, 39, 39, 1, 307200, 0x21c4a16f +0, 40, 40, 1, 307200, 0xb6505ff0 +0, 41, 41, 1, 307200, 0x12562a42 +0, 42, 42, 1, 307200, 0x3335e451 +0, 43, 43, 1, 307200, 0x6f1274cf +0, 44, 44, 1, 307200, 0xa52e71d2 +0, 45, 45, 1, 307200, 0x4fda2634 +0, 46, 46, 1, 307200, 0x5b48d624 +0, 47, 47, 1, 307200, 0xa9505af8 +0, 48, 48, 1, 307200, 0xc2624880 +0, 49, 49, 1, 307200, 0x4eb317a5 diff --git a/tests/ref/fate/filter-framerate-12bit-up b/tests/ref/fate/filter-framerate-12bit-up new file mode 100644 index 000000000..ef709a8fc --- /dev/null +++ b/tests/ref/fate/filter-framerate-12bit-up @@ -0,0 +1,65 @@ +#tb 0: 1/60 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 307200, 0xb49cf016 +0, 1, 1, 1, 307200, 0xbe4390ed +0, 2, 2, 1, 307200, 0xe4ca172c +0, 3, 3, 1, 307200, 0x5378b13c +0, 4, 4, 1, 307200, 0xe742454c +0, 5, 5, 1, 307200, 0x68f620cd +0, 6, 6, 1, 307200, 0x83dbe321 +0, 7, 7, 1, 307200, 0x7135c77d +0, 8, 8, 1, 307200, 0xc69a864a +0, 9, 9, 1, 307200, 0xc5c8b0f8 +0, 10, 10, 1, 307200, 0xf6ee5d1c +0, 11, 11, 1, 307200, 0xab36763c +0, 12, 12, 1, 307200, 0xcba4c6bb +0, 13, 13, 1, 307200, 0xb379c679 +0, 14, 14, 1, 307200, 0x63339757 +0, 15, 15, 1, 307200, 0x4bdfd3ca +0, 16, 16, 1, 307200, 0x14e09691 +0, 17, 17, 1, 307200, 0x5dc7c711 +0, 18, 18, 1, 307200, 0xda8c6c41 +0, 19, 19, 1, 307200, 0xe187c6b6 +0, 20, 20, 1, 307200, 0x5d8b76ab +0, 21, 21, 1, 307200, 0xe2337c57 +0, 22, 22, 1, 307200, 0x492117d7 +0, 23, 23, 1, 307200, 0xf0df5ea3 +0, 24, 24, 1, 307200, 0x4237e892 +0, 25, 25, 1, 307200, 0x4f61a7d7 +0, 26, 26, 1, 307200, 0x2ba55745 +0, 27, 27, 1, 307200, 0x0e058165 +0, 28, 28, 1, 307200, 0xe371f352 +0, 29, 29, 1, 307200, 0xab562bfe +0, 30, 30, 1, 307200, 0x0b58bcf7 +0, 31, 31, 1, 307200, 0xf1a04a1e +0, 32, 32, 1, 307200, 0xb466f1d6 +0, 33, 33, 1, 307200, 0x3ed6b5d8 +0, 34, 34, 1, 307200, 0x05091a43 +0, 35, 35, 1, 307200, 0xbfb20efc +0, 36, 36, 1, 307200, 0xbd67248a +0, 37, 37, 1, 307200, 0x58001b29 +0, 38, 38, 1, 307200, 0x6ec5bbb1 +0, 39, 39, 1, 307200, 0x0e4455cd +0, 40, 40, 1, 307200, 0x5c2c3213 +0, 41, 41, 1, 307200, 0x976f6900 +0, 42, 42, 1, 307200, 0x58adad3f +0, 43, 43, 1, 307200, 0x8dbb14f0 +0, 44, 44, 1, 307200, 0x49163226 +0, 45, 45, 1, 307200, 0xaac8e1ca +0, 46, 46, 1, 307200, 0x07cc8404 +0, 47, 47, 1, 307200, 0xbf85c994 +0, 48, 48, 1, 307200, 0x22ed5b5a +0, 49, 49, 1, 307200, 0x1bf7df1e +0, 50, 50, 1, 307200, 0x3a21b4d2 +0, 51, 51, 1, 307200, 0xbd5edb2d +0, 52, 52, 1, 307200, 0x336a8437 +0, 53, 53, 1, 307200, 0x02c7e528 +0, 54, 54, 1, 307200, 0xba073e6f +0, 55, 55, 1, 307200, 0x9e25ddfe +0, 56, 56, 1, 307200, 0x8cf55128 +0, 57, 57, 1, 307200, 0x4e740b42 +0, 58, 58, 1, 307200, 0x8e7e705c +0, 59, 59, 1, 307200, 0xe73f29ef diff --git a/tests/ref/fate/filter-framerate-up b/tests/ref/fate/filter-framerate-up index b2af9cb87..15bf6d815 100644 --- a/tests/ref/fate/filter-framerate-up +++ b/tests/ref/fate/filter-framerate-up @@ -6,10 +6,10 @@ 0, 0, 0, 1, 115200, 0x3744b3ed 0, 1, 1, 1, 115200, 0xc44bdc65 0, 2, 2, 1, 115200, 0xa17f0d74 -0, 3, 3, 1, 115200, 0xb0c83274 +0, 3, 3, 1, 115200, 0xd72532a9 0, 4, 4, 1, 115200, 0x232d6368 0, 5, 5, 1, 115200, 0x6e318ba0 0, 6, 6, 1, 115200, 0x247e846e 0, 7, 7, 1, 115200, 0x89e27599 -0, 8, 8, 1, 115200, 0x31c5704e +0, 8, 8, 1, 115200, 0x68536eac 0, 9, 9, 1, 115200, 0x97e45fec diff --git a/tests/ref/fate/filter-pixfmts-lut b/tests/ref/fate/filter-pixfmts-lut index db3fd417b..6cf798ad7 100644 --- a/tests/ref/fate/filter-pixfmts-lut +++ b/tests/ref/fate/filter-pixfmts-lut @@ -12,6 +12,11 @@ gbrp12le c5a4b89571f7095eb737ad9fd6b1ee08 gbrp14le bdfdfd6f36c60497d1cdae791f3cc117 gbrp16le df095ef3a20995935cfcaf144afc68b6 gbrp9le a8c4e29f4cb627db81ba053e0853e702 +gray 20b14b5e26cd11300ed1249e04082170 +gray10le 8f4140b55e847cc423002b89666db5ea +gray12le ea89c02f6b3af49ddaf13364ed33d86d +gray16le aa10599924fb2440fa12b76e90f57dcb +gray9le 7d9cc9ad6118674c547a54281d10cf05 rgb24 a356171207723a580e7d277078072005 rgb48le 5c7dd8575836d18c91e09f1915cf9aa9 rgba 7bc854c2698b78af3e9159a19c2d9d21 diff --git a/tests/ref/fate/fitsdec-gbrap16 b/tests/ref/fate/fitsdec-gbrap16le similarity index 100% rename from tests/ref/fate/fitsdec-gbrap16 rename to tests/ref/fate/fitsdec-gbrap16le diff --git a/tests/ref/fate/fmvc-type1 b/tests/ref/fate/fmvc-type1 new file mode 100644 index 000000000..d59de047e --- /dev/null +++ b/tests/ref/fate/fmvc-type1 @@ -0,0 +1,11 @@ +#tb 0: 1/15 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 664x382 +#sar 0: 0/1 +0, 0, 0, 1, 760944, 0x2feb1453 +0, 1, 1, 1, 760944, 0x9677ebf8 +0, 2, 2, 1, 760944, 0x83d2ed49 +0, 3, 3, 1, 760944, 0x9ab6c63d +0, 4, 4, 1, 760944, 0x1820189c +0, 5, 5, 1, 760944, 0x4b94f521 diff --git a/tests/ref/fate/fmvc-type2 b/tests/ref/fate/fmvc-type2 new file mode 100644 index 000000000..60c630803 --- /dev/null +++ b/tests/ref/fate/fmvc-type2 @@ -0,0 +1,33 @@ +#tb 0: 1/10 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 768x576 +#sar 0: 0/1 +0, 0, 0, 1, 1327104, 0xa73c232d +0, 1, 1, 1, 1327104, 0xa73c232d +0, 2, 2, 1, 1327104, 0xa73c232d +0, 3, 3, 1, 1327104, 0xf14e05be +0, 4, 4, 1, 1327104, 0xd8c03726 +0, 5, 5, 1, 1327104, 0x16e8447a +0, 6, 6, 1, 1327104, 0x8dfd94d2 +0, 7, 7, 1, 1327104, 0x3550833b +0, 8, 8, 1, 1327104, 0x74bd2959 +0, 9, 9, 1, 1327104, 0xc2b4505c +0, 10, 10, 1, 1327104, 0x7c6999cd +0, 11, 11, 1, 1327104, 0xb6562711 +0, 12, 12, 1, 1327104, 0x50993565 +0, 13, 13, 1, 1327104, 0x579549d2 +0, 14, 14, 1, 1327104, 0xb17170f6 +0, 15, 15, 1, 1327104, 0xc7d87708 +0, 16, 16, 1, 1327104, 0xdb3879da +0, 17, 17, 1, 1327104, 0xdb3879da +0, 18, 18, 1, 1327104, 0xdb3879da +0, 19, 19, 1, 1327104, 0x6f1c5c01 +0, 20, 20, 1, 1327104, 0xd9d15c01 +0, 21, 21, 1, 1327104, 0x826f0bab +0, 22, 22, 1, 1327104, 0xf25b041d +0, 23, 23, 1, 1327104, 0xc85a041d +0, 24, 24, 1, 1327104, 0xc85a041d +0, 25, 25, 1, 1327104, 0xc85a041d +0, 26, 26, 1, 1327104, 0xc85a041d +0, 27, 27, 1, 1327104, 0xc54cc6ae diff --git a/tests/ref/fate/h264-ref-pic-mod-overflow b/tests/ref/fate/h264-ref-pic-mod-overflow new file mode 100644 index 000000000..d4386c026 --- /dev/null +++ b/tests/ref/fate/h264-ref-pic-mod-overflow @@ -0,0 +1,25 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 1/1 +0, 0, 0, 1, 3110400, 0x5cd0bee9 +0, 1, 1, 1, 3110400, 0x19d0155c +0, 2, 2, 1, 3110400, 0x3519be4b +0, 3, 3, 1, 3110400, 0x87dc6708 +0, 4, 4, 1, 3110400, 0xef3c1056 +0, 5, 5, 1, 3110400, 0x5064aad2 +0, 6, 6, 1, 3110400, 0xbfb35057 +0, 7, 7, 1, 3110400, 0x6089eb95 +0, 8, 8, 1, 3110400, 0x85de8dea +0, 9, 9, 1, 3110400, 0x216b1e5a +0, 10, 10, 1, 3110400, 0xba73bdc4 +0, 11, 11, 1, 3110400, 0x536e437a +0, 12, 12, 1, 3110400, 0x4be0cdbd +0, 13, 13, 1, 3110400, 0x7316462d +0, 14, 14, 1, 3110400, 0x80eb8622 +0, 15, 15, 1, 3110400, 0xa612a70b +0, 16, 16, 1, 3110400, 0x9ff65345 +0, 17, 17, 1, 3110400, 0x57003dfa +0, 18, 18, 1, 3110400, 0xf29e036e +0, 19, 19, 1, 3110400, 0x70285363 diff --git a/tests/ref/fate/hap-alpha-only-nosnappy-128x72 b/tests/ref/fate/hap-alpha-only-nosnappy-128x72 new file mode 100644 index 000000000..d9b1b5614 --- /dev/null +++ b/tests/ref/fate/hap-alpha-only-nosnappy-128x72 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x72 +#sar 0: 1/1 +0, 0, 0, 1, 9216, 0x5967036f diff --git a/tests/ref/fate/hap-alpha-only-snappy-127x71 b/tests/ref/fate/hap-alpha-only-snappy-127x71 new file mode 100644 index 000000000..1559204ca --- /dev/null +++ b/tests/ref/fate/hap-alpha-only-snappy-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 9017, 0xc390c38c diff --git a/tests/ref/fate/hapqa-nosnappy-127x71 b/tests/ref/fate/hapqa-nosnappy-127x71 new file mode 100644 index 000000000..36069b484 --- /dev/null +++ b/tests/ref/fate/hapqa-nosnappy-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 36068, 0x16c0a011 diff --git a/tests/ref/fate/hapqa-snappy1-127x71 b/tests/ref/fate/hapqa-snappy1-127x71 new file mode 100644 index 000000000..36069b484 --- /dev/null +++ b/tests/ref/fate/hapqa-snappy1-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 36068, 0x16c0a011 diff --git a/tests/ref/fate/hapqa-snappy16-127x71 b/tests/ref/fate/hapqa-snappy16-127x71 new file mode 100644 index 000000000..36069b484 --- /dev/null +++ b/tests/ref/fate/hapqa-snappy16-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 36068, 0x16c0a011 diff --git a/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_3 b/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_3 new file mode 100644 index 000000000..54f4db8c5 --- /dev/null +++ b/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_3 @@ -0,0 +1,7 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 400x384 +#sar 0: 0/1 +0, 0, 0, 1, 921600, 0x702f0d67 +0, 1, 1, 1, 921600, 0x99822b52 diff --git a/tests/ref/fate/hevc-skiploopfilter b/tests/ref/fate/hevc-skiploopfilter new file mode 100644 index 000000000..9c29909c5 --- /dev/null +++ b/tests/ref/fate/hevc-skiploopfilter @@ -0,0 +1,14 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 3110400, 076c9288843ef1197a8cbef7f9a13fee +0, 1, 1, 1, 3110400, 6190eeea952805ebde69d22961aaeb45 +0, 2, 2, 1, 3110400, 9aaa5111d5e6b25dcf5ddd19c58f17f7 +0, 3, 3, 1, 3110400, 52a487e5f71b314e33e6632b4496f0a6 +0, 4, 4, 1, 3110400, 13abb1c78313705b57a8298dc1e6c0e2 diff --git a/tests/ref/fate/mov-440hz-10ms b/tests/ref/fate/mov-440hz-10ms new file mode 100644 index 000000000..498879e52 --- /dev/null +++ b/tests/ref/fate/mov-440hz-10ms @@ -0,0 +1,11 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +#stream#, dts, pts, duration, size, hash +0, 0, 0, 960, 1920, 44e7e48ff08835ce30e93c7971dae7df diff --git a/tests/ref/fate/mov-bbi-elst-starts-b b/tests/ref/fate/mov-bbi-elst-starts-b new file mode 100644 index 000000000..3ba28b5e7 --- /dev/null +++ b/tests/ref/fate/mov-bbi-elst-starts-b @@ -0,0 +1,391 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 1/1 +#tb 1: 1/48000 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 48000 +#channel_layout 1: 3 +#channel_layout_name 1: stereo +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 3110400, e9454409af76038dbe56e834921d2fa8 +1, 0, 0, 1024, 4096, 620f0b67a91f7f74151bc5be745b7110 +1, 1024, 1024, 1024, 4096, 4963ab641585142fbac06502873fb6d3 +0, 1, 1, 1, 3110400, 37aa620e494d22ba248feea9a5a869a0 +1, 2048, 2048, 1024, 4096, 80649ae10d2587264fcb43c7dc25e61b +1, 3072, 3072, 1024, 4096, 01ec94c18060be08988e8b9b1c9de822 +0, 2, 2, 1, 3110400, 7b8be9619e4e1d618ab1ed85aff3957b +1, 4096, 4096, 1024, 4096, 3f8342da3124e22b89211c2f233eb5b2 +0, 3, 3, 1, 3110400, 756a4551420853bc3ae444e6b86169f3 +1, 5120, 5120, 1024, 4096, 4832d1a3f7d8aaceb0489c1ca0706d31 +1, 6144, 6144, 1024, 4096, 7e89f1e8318ed54d81e4efe3c679515f +0, 4, 4, 1, 3110400, 94a93c1669a96ebf41a7258177849396 +1, 7168, 7168, 1024, 4096, d73468c68e92c9e2939eb30d66a45bc2 +0, 5, 5, 1, 3110400, 5d1c49d3f43cd472683e4a039e376af5 +1, 8192, 8192, 1024, 4096, 72e1020c1bb961cb1c177f97e427edb9 +1, 9216, 9216, 1024, 4096, 1a4773af7080bd904a3b14c12a8028fa +0, 6, 6, 1, 3110400, e0e88cc34b0a9d7963cddf554a3909f0 +1, 10240, 10240, 1024, 4096, d39ae1809032c4807efe41520302bd37 +0, 7, 7, 1, 3110400, 1f464f2427aa3842224803b6d67154f8 +1, 11264, 11264, 1024, 4096, e26af86998d1a9579127a97dbe45890b +1, 12288, 12288, 1024, 4096, 148e1ab102c1c62d9018095c7e934eea +0, 8, 8, 1, 3110400, e5d610b8e53203b5ccb01877acb3ac56 +1, 13312, 13312, 1024, 4096, 96582c941184ad967e9e91198775e61f +1, 14336, 14336, 1024, 4096, 8d2371bb1524d9d007ae44519b55a055 +0, 9, 9, 1, 3110400, d1363fbdffbb85a0affe660bfd09b98c +1, 15360, 15360, 1024, 4096, 6034c9e409d8dcdfd032b44f631e2362 +0, 10, 10, 1, 3110400, 130bb4c17e963b092a717325498c06c3 +1, 16384, 16384, 1024, 4096, 3649e9edc65a042c4c913c06c3f3bff7 +1, 17408, 17408, 1024, 4096, a4cdb0c4bed48d1f7c4918e5590a542d +0, 11, 11, 1, 3110400, a3cb7a37fef5d8a49815dd15970c1f3d +1, 18432, 18432, 1024, 4096, a130e8ba9a47df0c76edf5c3ece5762f +0, 12, 12, 1, 3110400, 7dc4a4334fa9bb61f2ad56b3d059b3f7 +1, 19456, 19456, 1024, 4096, cf76a132c205c29a0b7042599973fda4 +1, 20480, 20480, 1024, 4096, b9b7d819599bb6d7cd53cc1bc0810ca7 +0, 13, 13, 1, 3110400, ccda106ec5899787c3bc8679ee052854 +1, 21504, 21504, 1024, 4096, 3d0d6ef8318a94416a56108248e6cad3 +0, 14, 14, 1, 3110400, 4254c7b01a67a0810bf234ba7b1f59d0 +1, 22528, 22528, 1024, 4096, a8a082b4c521d2e7fc990f54e3580a9e +1, 23552, 23552, 1024, 4096, 60b36c268bc98093f35a7c90c64b507c +0, 15, 15, 1, 3110400, 6c0acd9781cfecaf9a10fe91f8d6ec41 +1, 24576, 24576, 1024, 4096, c5211b49eb51cea4c16079eb54df3d12 +1, 25600, 25600, 1024, 4096, dddd55a31e8a65110a89de1af67861b0 +0, 16, 16, 1, 3110400, 2a9d5db0bc2f54e2c66834db64386bb7 +1, 26624, 26624, 1024, 4096, 0c220f1d405bb463469b54fa126a2c41 +0, 17, 17, 1, 3110400, 0140f515be87da399061764050d15b16 +1, 27648, 27648, 1024, 4096, 11d740234a9a4dd28e3191e258fc8e3b +1, 28672, 28672, 1024, 4096, e456943c722a9807669f57776dcb8c5d +0, 18, 18, 1, 3110400, cad554fe221fbd8ee848facebd7b24d2 +1, 29696, 29696, 1024, 4096, 3c13165d648f46c3e3e699b874da372a +0, 19, 19, 1, 3110400, 1e8474911cb1bd831808dc2beba540c0 +1, 30720, 30720, 1024, 4096, 7e7a46e3360f884507c95f640cd6f532 +1, 31744, 31744, 1024, 4096, 420d047ee4d55b7af2d97c5116e25d37 +0, 20, 20, 1, 3110400, f39c483fbf3c598c38cf543abad2c03c +1, 32768, 32768, 1024, 4096, b3334bcd2ed3b2ab32ac13c24a8d1322 +0, 21, 21, 1, 3110400, 3b21171a003827a203c0c5853c36893e +1, 33792, 33792, 1024, 4096, 1472898e0d4fafd52fc0adb789e06987 +1, 34816, 34816, 1024, 4096, f3e7c33d92578fa5eb90933491106c37 +0, 22, 22, 1, 3110400, 40e8733f93c468cb58c3921c80f81c68 +1, 35840, 35840, 1024, 4096, 7d7f8e8f542be9291b7895472f8cf0a7 +0, 23, 23, 1, 3110400, a2d716f215af7d778bd605decae201dd +1, 36864, 36864, 1024, 4096, 66e2e35d40beb6e1df30d4d180661d4b +1, 37888, 37888, 1024, 4096, 8fc0c16fc3ec5db47e437263b429406b +0, 24, 24, 1, 3110400, e6fb8d3f1c9747f185b50eded67ff0ab +1, 38912, 38912, 1024, 4096, dd6331f430abf41dade4e4a85784745f +1, 39936, 39936, 1024, 4096, 5c693b37419fe43fb83b715d4f7083ec +0, 25, 25, 1, 3110400, fe4e0cf566674672ad043f24eae02e63 +1, 40960, 40960, 1024, 4096, 9e13b054c07feac0fad601ed4823996e +0, 26, 26, 1, 3110400, f57d4d32012dfcb14a270bdc90812e5e +1, 41984, 41984, 1024, 4096, dbffea22781b35088859868189e270aa +1, 43008, 43008, 1024, 4096, 59f1a985d7a96273bf48be9dc8a7d4d2 +0, 27, 27, 1, 3110400, fe7aa8c1754b9590fe75b783d4e126ed +1, 44032, 44032, 1024, 4096, b07e02d0bfecbde9b48e6e83952aa3c7 +0, 28, 28, 1, 3110400, 29ae6e541021bf481c8937c37ac34570 +1, 45056, 45056, 1024, 4096, d0dfca31885ac1d21fe42bb26e3b11ec +1, 46080, 46080, 1024, 4096, 5479670aea3a4d07a61b9edcc2113c7b +0, 29, 29, 1, 3110400, 211e0803b5a704c7ef1c36fc5c182710 +1, 47104, 47104, 1024, 4096, 0118d7fc0d0f8462647f37aa6d82c8fc +0, 30, 30, 1, 3110400, a4ea3a4686d214ad54fcdce63f8c2dc0 +1, 48128, 48128, 1024, 4096, cc2b22d4c7497accb6b194968b407e10 +1, 49152, 49152, 1024, 4096, fe8d30c082a3608b8ccf5e3d6f4b0ddb +0, 31, 31, 1, 3110400, 8af971cf637609534ec59b6f29a3666e +1, 50176, 50176, 1024, 4096, ed15a6aa2d87395b47888f744f41df30 +1, 51200, 51200, 1024, 4096, 8d4971ee25d274822cceaa00cc8df1a1 +0, 32, 32, 1, 3110400, 8cfe93dfd76e4f97cc04a145bb559af5 +1, 52224, 52224, 1024, 4096, 799f1c9cac6c3cedaac80cc6b26df827 +0, 33, 33, 1, 3110400, 691fe61398016f767ea7ba781ef72953 +1, 53248, 53248, 1024, 4096, 40cbefbb455231c0f21af129e2504395 +1, 54272, 54272, 1024, 4096, 05eb1731cb93ff68815e92f0a528d4d7 +0, 34, 34, 1, 3110400, 7eaf5bc5e942f8218f46c9c505d7b58c +1, 55296, 55296, 1024, 4096, de96fa062c59b6b3b88731e60e02d040 +0, 35, 35, 1, 3110400, feacc8282186935e310ec2dccbb79239 +1, 56320, 56320, 1024, 4096, 14d38d89079c1b7801987c5315477d11 +1, 57344, 57344, 1024, 4096, 9a0029ae7fc7e029402ec29536288cff +0, 36, 36, 1, 3110400, a5dfb5c4c23e647e2c77dd117e4ed714 +1, 58368, 58368, 1024, 4096, 83925a6ebf953e6b711d3042c95ffe51 +0, 37, 37, 1, 3110400, da9306c2872788ba2a587eab7f597f13 +1, 59392, 59392, 1024, 4096, 5b332b22a2a8ae72cbf8154d2cfd9b5d +1, 60416, 60416, 1024, 4096, 8dcd5041b49036e43f74819439a6db63 +0, 38, 38, 1, 3110400, 19d14a655aa02cc2767afd9ed9bc2ff4 +1, 61440, 61440, 1024, 4096, 90ea3ac56003b4f1c0242a611746b76a +0, 39, 39, 1, 3110400, 4d9e6455fb71d5cd511dddf894b4f7d8 +1, 62464, 62464, 1024, 4096, 6ed9f815739e6e3b8ed125688f693d5f +1, 63488, 63488, 1024, 4096, e056b91f4875029af3c29a26e37380a1 +0, 40, 40, 1, 3110400, 052c32c00bc1b40d5270f4b5c4d34d6b +1, 64512, 64512, 1024, 4096, 36ff82cb34ffc9ea60b1fbc8d3edd9f1 +1, 65536, 65536, 1024, 4096, 975c2d6080532645be510241d52b788c +0, 41, 41, 1, 3110400, 645e0c3eb8599c2cc712a97cbae9d1d3 +1, 66560, 66560, 1024, 4096, 9a53c620f19d5bb733c8bd068137ba3a +0, 42, 42, 1, 3110400, d0b3fe092511fed0e384ffad85f6ae3c +1, 67584, 67584, 1024, 4096, 482365611c86663b70a13511d8194282 +1, 68608, 68608, 1024, 4096, 4f9002718a7103a4b15b96e9e08a2cfd +0, 43, 43, 1, 3110400, 131c090f806658ffbb4949b3310a6348 +1, 69632, 69632, 1024, 4096, 2301e3336164fe298b85006b0e7dc0b8 +0, 44, 44, 1, 3110400, 71e8042ed01a1bbe971417d87685dda1 +1, 70656, 70656, 1024, 4096, d8b4c47bb3f58a70109d70edaea9916b +1, 71680, 71680, 1024, 4096, ff87ca54ad112c083b1cc25043429410 +0, 45, 45, 1, 3110400, 948cc8d7eceb2e512c8660063143557b +1, 72704, 72704, 1024, 4096, eee9c7fd3c78681fcfcdf40ed7ee2c6b +0, 46, 46, 1, 3110400, 8b580d4f620af52ac0a5702197f5e9d6 +1, 73728, 73728, 1024, 4096, d05a2d810e2c201cff9e115c48cff977 +1, 74752, 74752, 1024, 4096, 5ef14640b86062c99427e0177b33657c +0, 47, 47, 1, 3110400, a30bfc0727c6abb477751969c1b1450c +1, 75776, 75776, 1024, 4096, 92398dd17af6362aa81fe8a9aad0af01 +1, 76800, 76800, 1024, 4096, 131b910e0af30e5250726b3d4a5f4f10 +0, 48, 48, 1, 3110400, 28381142e60e9011d0cd75e7881c1956 +1, 77824, 77824, 1024, 4096, 50157f3541acd42d2c460e125a9f2393 +0, 49, 49, 1, 3110400, 1b4bdae40d76ed7625f85da7c5289360 +1, 78848, 78848, 1024, 4096, 266fd18529d95b7347e9a019271056fc +1, 79872, 79872, 1024, 4096, 2f9a347ce750501f2e4d0a36c95bc8b0 +0, 50, 50, 1, 3110400, 354fb545adf6082dc57b8077ba1466ad +1, 80896, 80896, 1024, 4096, 0f8b0626ef01d0e941914d7810945aa1 +0, 51, 51, 1, 3110400, c969f21be0dcbef6b232d3f0a9e3f189 +1, 81920, 81920, 1024, 4096, 51da6b0c3d5daddb8f4635d692b0e8ba +1, 82944, 82944, 1024, 4096, aac8a7152103243dabd94e2a37caf53f +0, 52, 52, 1, 3110400, 4ff19ab89ebe466e8ce3df0ba25b6b0a +1, 83968, 83968, 1024, 4096, 50c8d5b0a373c07ecb66ca33e087a299 +0, 53, 53, 1, 3110400, 49f601932c19ae8d405771e9cfd4f9e8 +1, 84992, 84992, 1024, 4096, 2abd975868c9805fa456a08f1ab16c91 +1, 86016, 86016, 1024, 4096, 56309326bc80a6216b048934713db907 +0, 54, 54, 1, 3110400, c75d2221327d5953b013fdc9d36dbcd3 +1, 87040, 87040, 1024, 4096, 470fd4997793f53ad2b21b47c6b98bb1 +1, 88064, 88064, 1024, 4096, 1aed57e8ba33350711e1ff668c906953 +0, 55, 55, 1, 3110400, 6c8b8c6012b6ac36c4c2a3ab5629ec61 +1, 89088, 89088, 1024, 4096, 9e910446a3b8d30f270c05aca011704d +0, 56, 56, 1, 3110400, 44a05705ad5cb730e7244c36b4f94771 +1, 90112, 90112, 1024, 4096, af6c036d66dd5bb5c250f16207173180 +1, 91136, 91136, 1024, 4096, de76d587f349fe597e65cb1f51bdcc34 +0, 57, 57, 1, 3110400, 0ee53224814c84224525181aacbd9a39 +1, 92160, 92160, 1024, 4096, 7abab5bffebfcc801a11f6b7905a13c9 +0, 58, 58, 1, 3110400, cd7797aa75c96a2a71e939ea6b677310 +1, 93184, 93184, 1024, 4096, 3567caaaea75b1cda5920fd6dbf2a016 +1, 94208, 94208, 1024, 4096, 2a6848418d829a273b85620e5b59cabe +0, 59, 59, 1, 3110400, ac2207156da29fd33ca1c66224445bbc +1, 95232, 95232, 1024, 4096, 79d0c213acefa2bc00de4fd455b34df9 +0, 60, 60, 1, 3110400, 1669c959bd2b6f245cc83ea00d0de83f +1, 96256, 96256, 1024, 4096, 267414473e0e7c75c7c1dde7be001762 +1, 97280, 97280, 1024, 4096, 893107ddb969cbc25a5aa8c564559836 +0, 61, 61, 1, 3110400, a74e6586842a4c877fa9a123e7b8ef94 +1, 98304, 98304, 1024, 4096, 1555a7117d5254afef3e36b1d0a9edd2 +0, 62, 62, 1, 3110400, 5af4edbf8a77ead17f4891cbac6d72be +1, 99328, 99328, 1024, 4096, dd92c3241e45d54cc072fc0307d1850c +1, 100352, 100352, 1024, 4096, 95c55b1767ddea9af80edbb32e2b4dbc +0, 63, 63, 1, 3110400, 52598cb5f3cb75bc401370118bcb2c49 +1, 101376, 101376, 1024, 4096, 1d133e7a83f0cf96a6e9cee90d17975a +1, 102400, 102400, 1024, 4096, b71b82a4abcde640a46fcc3bd6930d51 +0, 64, 64, 1, 3110400, d44aa05de89e71b3af23de9afbb2a3b1 +1, 103424, 103424, 1024, 4096, 57697c6f8e32dda304b77b2881b5011d +0, 65, 65, 1, 3110400, 161fd1ff8b477a137e113ce7e6ac26f7 +1, 104448, 104448, 1024, 4096, 592725ee5ee2adfc02e8c189f402a3d9 +1, 105472, 105472, 1024, 4096, 2b1073734ea08c0cfeeaab15ad04aa60 +0, 66, 66, 1, 3110400, b9b5efaf5f74954897882b0f09a5c088 +1, 106496, 106496, 1024, 4096, 18f2a5daef2293e690fe0915127cb795 +0, 67, 67, 1, 3110400, 1405f3d5e75c2ffd390b46f7def70478 +1, 107520, 107520, 1024, 4096, 4fa75ff788019d99f6ab0ad2ee5cc3d4 +1, 108544, 108544, 1024, 4096, d40f1172149821d84130990d5acd9395 +0, 68, 68, 1, 3110400, 3bf19eda056d5fc609662bf5ca8e3b33 +1, 109568, 109568, 1024, 4096, edae14a39d1034cfce5655337df2206e +0, 69, 69, 1, 3110400, 8ba1925dc6b38a340e51aa234b5ff4df +1, 110592, 110592, 1024, 4096, 574a6a3b427314c2eb48226d2d7ce67d +1, 111616, 111616, 1024, 4096, ebf13ab2795c091f15b9086d5bf2e11e +0, 70, 70, 1, 3110400, 301aecbe3f8bf3831d6de540a568abbc +1, 112640, 112640, 1024, 4096, 074c63c81345804c7437de33cb5e355f +1, 113664, 113664, 1024, 4096, 58da9edb5e278e292cebebf6b26435b0 +0, 71, 71, 1, 3110400, 388565f088710aeb0f50ecdf8ef0ee86 +1, 114688, 114688, 1024, 4096, ce75fd079a21e0637900ac491c4fbc36 +0, 72, 72, 1, 3110400, df27196ff8da5085c58979deeae9c4a1 +1, 115712, 115712, 1024, 4096, 92153c14aeabfb4b4546c340201202b0 +1, 116736, 116736, 1024, 4096, f02e8d23ee0ca80713b4458873ce724f +0, 73, 73, 1, 3110400, 750226c84aae270449e0a20751218217 +1, 117760, 117760, 1024, 4096, 0adec04349d269f7dde27c59c7077954 +0, 74, 74, 1, 3110400, 076d4246e5494e6d5cf8ffb09be3a751 +1, 118784, 118784, 1024, 4096, 4408d6824ca6c2080fd76c1ab840382c +1, 119808, 119808, 1024, 4096, c3603730a05cff479148d9b69b7ed2e8 +0, 75, 75, 1, 3110400, 9f626289f18a3482628b511840deaa10 +1, 120832, 120832, 1024, 4096, 25a6af5ef98aae3c40610e58ca65b8a9 +0, 76, 76, 1, 3110400, f925e3ff4bda9962a313b6ac21a201f1 +1, 121856, 121856, 1024, 4096, 5ad875e4437059157f0f3a5ec911e741 +1, 122880, 122880, 1024, 4096, cfc06fdc755579be7440fca797d81191 +0, 77, 77, 1, 3110400, 1d893861545e804944c519e580204988 +1, 123904, 123904, 1024, 4096, 7c783d7b973bb8048eeaa568297cfa35 +0, 78, 78, 1, 3110400, 4d42fca73082fde38020a8fec0b27db2 +1, 124928, 124928, 1024, 4096, cae22b99b2c6fea527fb5c038d3765f8 +1, 125952, 125952, 1024, 4096, fc4b5ef5a5a28102bf782b8732fc2993 +0, 79, 79, 1, 3110400, ed88335480ef00aedcf73c3a8712705c +1, 126976, 126976, 1024, 4096, e278968277ccc64992ba6bb73ad9909d +1, 128000, 128000, 1024, 4096, e2eb81d30fe7fa901eaf295fca8bc8b8 +0, 80, 80, 1, 3110400, 968ba4c93f80cb8c6fbfaccb765c3d70 +1, 129024, 129024, 1024, 4096, 5a9b99c0639bd80ef7f20971590e23c7 +0, 81, 81, 1, 3110400, 01ef52b0a18f46556ba9e00d1b0c77af +1, 130048, 130048, 1024, 4096, 2765d109f09efa2f2661dfd2e666f25c +1, 131072, 131072, 1024, 4096, 1ff52d5870cd667388fe69f48e228fc6 +0, 82, 82, 1, 3110400, 54582f2ae6878b37cbd1b5c576fd09c7 +1, 132096, 132096, 1024, 4096, 3612470a58bb5eab26239fbd3d097866 +0, 83, 83, 1, 3110400, fec6585d244257b52c90cfa19b22fd7c +1, 133120, 133120, 1024, 4096, be170a1e3eba4c53b0e2fc8b795c7767 +1, 134144, 134144, 1024, 4096, abb85ab4987c50e05ecab0e831d53fd6 +0, 84, 84, 1, 3110400, be1e0237c5d8bab98aa75a91e0d4bd9b +1, 135168, 135168, 1024, 4096, 2e9b5c17dcaf77f171544c0eee6cf191 +0, 85, 85, 1, 3110400, 1138a9f316d1a2a9ae3c42d777561595 +1, 136192, 136192, 1024, 4096, 54c1c5d9c706e1999b2243828736c98d +1, 137216, 137216, 1024, 4096, 7b482f85e123981e8eb37c364b2f4bbe +0, 86, 86, 1, 3110400, 62da42e9e8643ec9b1299bbeaffa4be5 +1, 138240, 138240, 1024, 4096, 0be223967283ac3a0029fad458176155 +1, 139264, 139264, 1024, 4096, 8ec0c4054d484ebf8d68e32c3ffb5924 +0, 87, 87, 1, 3110400, 55fc4dcfb7f8bab37518884fc6747416 +1, 140288, 140288, 1024, 4096, 0308762a4362acbf1c9e1e62e5055880 +0, 88, 88, 1, 3110400, 51be69793bfae3fe078d04e8dee3a48b +1, 141312, 141312, 1024, 4096, 56a18f795b25ef93d27a53a9f6a87ec9 +1, 142336, 142336, 1024, 4096, ad46ed8c3ac23b79bbd066e43b77f4e6 +0, 89, 89, 1, 3110400, 363b794880a2cc06e5be4626c6847c19 +1, 143360, 143360, 1024, 4096, 62719a7d4521ac82957ce3f52ba21854 +0, 90, 90, 1, 3110400, cd1d585cf9cb68f72f7d6a0ec9ab96ab +1, 144384, 144384, 1024, 4096, 8854128aa8377ad5e52af990d4642ef5 +1, 145408, 145408, 1024, 4096, 38827bf7a129f92062b90fcf03ba80c1 +0, 91, 91, 1, 3110400, 138f8686ee7294bf4af072cee7043f52 +1, 146432, 146432, 1024, 4096, 24d4e112b275116dcb512e6b283487e3 +0, 92, 92, 1, 3110400, 137c1bdc2bb6fa1e181f84b09c14e0b6 +1, 147456, 147456, 1024, 4096, 03c374d9d72df87f99427fe1045be8da +1, 148480, 148480, 1024, 4096, c0c5a8fd24d5a9f535118ec266468976 +0, 93, 93, 1, 3110400, e7bc46739c46ec886fc5059af72f772a +1, 149504, 149504, 1024, 4096, 3381472e14c42a06cdcf35774a0b3a9a +1, 150528, 150528, 1024, 4096, 4c07a7a02831675a686c6f31e2809e4a +0, 94, 94, 1, 3110400, db4c2aa67c76573e4880b029bef59c8d +1, 151552, 151552, 1024, 4096, adde928f734ffe6c07446c9d70214f74 +0, 95, 95, 1, 3110400, 3a287113ad2196420a0474243bd1813d +1, 152576, 152576, 1024, 4096, f1ff82fec1ef096090acbf60212b2b69 +1, 153600, 153600, 1024, 4096, e3b271991cc2cd4fdb56616443c9f3e8 +0, 96, 96, 1, 3110400, d3ed803ca1984f021802e6c7364cb57f +1, 154624, 154624, 1024, 4096, 025c3272bfb9f24ab687bc818d57d853 +0, 97, 97, 1, 3110400, 776d99c2973261c12e978fe9fe5c5794 +1, 155648, 155648, 1024, 4096, 8bb2de059194408962be4dfdd88775fc +1, 156672, 156672, 1024, 4096, eb61bcbcc9897d01f5645a0662dfbd6d +0, 98, 98, 1, 3110400, 62ee2ec1261db8544ded9db8c4442f15 +1, 157696, 157696, 1024, 4096, 48a3c897183538de9920e94417f54733 +0, 99, 99, 1, 3110400, 1bfabc7ab3701e112e76955a449431d7 +1, 158720, 158720, 1024, 4096, ffe159d137e51d8fd4d5b3639df563a3 +1, 159744, 159744, 1024, 4096, 7702e58e4ae075b6e12e863f8c5d908e +0, 100, 100, 1, 3110400, e03dfc70c25b77fc47ea42ddb8d5da5c +1, 160768, 160768, 1024, 4096, 2e2b497643e1b6bf13dd5e585ecd9092 +0, 101, 101, 1, 3110400, b0f0c308b49cb82fad3b4995cb60b6a1 +1, 161792, 161792, 1024, 4096, fcce76ebba5166966db792dfc77fda3d +1, 162816, 162816, 1024, 4096, ccf5a819e00ce8c5197ae5b2b827f3e5 +0, 102, 102, 1, 3110400, 627c888ea94dabff2aaf96c800a85f7a +1, 163840, 163840, 1024, 4096, 2385c9e205cfdd5e0b2ac54e9ef0f525 +1, 164864, 164864, 1024, 4096, 40214ba3f9bdc1bbb7d59e1fdb9def2f +0, 103, 103, 1, 3110400, f2231eac6e5885f61f470a5c6b65ceea +1, 165888, 165888, 1024, 4096, 52516e860beca0af0d80f79266c761cc +0, 104, 104, 1, 3110400, ec873def59cde7c114fe27ba1b2c25a6 +1, 166912, 166912, 1024, 4096, a25848945235fd70d1021b9a92dafd8d +1, 167936, 167936, 1024, 4096, 38c7a26c7a545df5fa1721ee3e820309 +0, 105, 105, 1, 3110400, 7a5e98b10b1f984b624bc6399a45dde2 +1, 168960, 168960, 1024, 4096, 506d3c3b34f060a0516011ca237cb6a5 +0, 106, 106, 1, 3110400, 180d7b9ef69a8ee32e5fcc3b9579c11f +1, 169984, 169984, 1024, 4096, 2ef3cd56dfc870a251bb97f4d474be84 +1, 171008, 171008, 1024, 4096, 383c82e600ebadddd0467cc3a9575f3e +0, 107, 107, 1, 3110400, 8c0107e3bda4c993131b361d598b4b4d +1, 172032, 172032, 1024, 4096, b99763cdc1d5412f89e7d1fcb3bd1c35 +0, 108, 108, 1, 3110400, 31e1ea32c3200a41814b5890b81c5211 +1, 173056, 173056, 1024, 4096, 7b3ecb91c63f7f86d6e96f305b3bd507 +1, 174080, 174080, 1024, 4096, 6945621a1ee0fbc68e7db786bc837f53 +0, 109, 109, 1, 3110400, f6223221be5136d03c87333c7f2113c5 +1, 175104, 175104, 1024, 4096, fb1de71ab0d840699834d583fbd3468e +1, 176128, 176128, 1024, 4096, 2a3b2d299d87f5b982156ae740fb7b46 +0, 110, 110, 1, 3110400, 325d0fb65e35826aebb0f80fc34f426f +1, 177152, 177152, 1024, 4096, 6462952e8555172110c37c579d45f63c +0, 111, 111, 1, 3110400, 1328e8c69419fe1c44fc6cfa1f648839 +1, 178176, 178176, 1024, 4096, 279537a0668d254a6710c935f2a7b8d7 +1, 179200, 179200, 1024, 4096, 286a27fee95bf8773ee8ea03621e9502 +0, 112, 112, 1, 3110400, b234f9aab6965e136bb283a2ad0fbb68 +1, 180224, 180224, 1024, 4096, 343413b110fe48674dddeba071440707 +0, 113, 113, 1, 3110400, 3961ef43173c69a28d2196f4fa11d37a +1, 181248, 181248, 1024, 4096, 66265d80629369fc9fffddbbe6ef104d +1, 182272, 182272, 1024, 4096, 3ff193da4d2168f97f17841f9669d33e +0, 114, 114, 1, 3110400, 943c6dd42254d346d81fd55bfad60573 +1, 183296, 183296, 1024, 4096, dd4074398b101502c29009687686e78d +0, 115, 115, 1, 3110400, 0028c32eacb6f4d77cb98cf856d266e4 +1, 184320, 184320, 1024, 4096, 562be444896543f259527081c7795597 +1, 185344, 185344, 1024, 4096, 145b4b260f2393ec1e3464d79c87fe8e +0, 116, 116, 1, 3110400, f478fe49fed80b92eaa182aa8e794077 +1, 186368, 186368, 1024, 4096, 6884ebc820bb41e61dc54a87bd55011e +0, 117, 117, 1, 3110400, 9a52c061c135bd75ee317fe48a2cddf8 +1, 187392, 187392, 1024, 4096, d2d8b2fd7a140a3f32d5649f8e507637 +1, 188416, 188416, 1024, 4096, 767071a409e0b07bd2cdb250c3c89607 +0, 118, 118, 1, 3110400, c327b95c8afa716f7719603d2b65679b +1, 189440, 189440, 1024, 4096, 64c4eed5e1b85e0728b1b0e3de30ffa1 +1, 190464, 190464, 1024, 4096, 11ffef7e85d9925a4032b3bcd9740e20 +0, 119, 119, 1, 3110400, edd3b4c4fa157940b9c252a7d94e6f55 +1, 191488, 191488, 1024, 4096, 99893421a493664be17085567e160280 +0, 120, 120, 1, 3110400, 5ccdffe7356a73d2d11eb7767ddfa396 +1, 192512, 192512, 1024, 4096, ea422077bc582aef4af5bf3ca3aa062a +1, 193536, 193536, 1024, 4096, a9e7ab9c45faf39f3cd1eee69c95d647 +0, 121, 121, 1, 3110400, 7c4d8083656581ccc666597da5559a46 +1, 194560, 194560, 1024, 4096, fc19b6642df3b85c7ebe684e705bf29d +0, 122, 122, 1, 3110400, 28cae533418f9a5d62869cbed0be384c +1, 195584, 195584, 1024, 4096, 39420620aea9d61b240691dada0f3063 +1, 196608, 196608, 1024, 4096, 5ad516a55655cdc2a3348badc2c7e5a1 +0, 123, 123, 1, 3110400, e9cf527a059c80461fd507bab4817069 +1, 197632, 197632, 1024, 4096, fa4f3d45c1cfc88088b4cd6f2924184d +0, 124, 124, 1, 3110400, a2f2518b8a25932afbb78523e8da289e +1, 198656, 198656, 1024, 4096, 689be1d6f84b136537df11b8ed22b540 +1, 199680, 199680, 1024, 4096, 9612dad6c93c75b6911f21997f2f7aee +0, 125, 125, 1, 3110400, 8fcbddce7f2a6c3bc380ad4cec17e51c +1, 200704, 200704, 1024, 4096, defe4b66e5dd9c6a527aeb9ebec04cdf +1, 201728, 201728, 1024, 4096, 0c39b71be01611d6be02b796aec2c6de +0, 126, 126, 1, 3110400, 32ff7b550d09821b2b1eb64c288559ba +1, 202752, 202752, 1024, 4096, 2150a3d6fdec61cd587b83217f9bbb2c +0, 127, 127, 1, 3110400, 1eb4e9050a6657ab9290ac58ed3aa93f +1, 203776, 203776, 1024, 4096, 4be35b36d46ca56b778ae0afdd1e4200 +1, 204800, 204800, 1024, 4096, fb79d3d9d0e4d590882cbd023bbcd00d +0, 128, 128, 1, 3110400, e45fd52e9ec3ad2d42740dd7cb5e971b +1, 205824, 205824, 1024, 4096, d4295a4a32d647a04ec0eab639c0d9fc +0, 129, 129, 1, 3110400, d625b970a797e37e465d9319471d40c3 +1, 206848, 206848, 1024, 4096, f03478b7689af9bdf6e67d271a4b3114 +1, 207872, 207872, 1024, 4096, 9fd97010278dc9147d8b73be9aacfb35 +0, 130, 130, 1, 3110400, b98e4a8fd994915a3dde3def26a9b171 +1, 208896, 208896, 1024, 4096, 2b9670707ad661b2125620d2156f11f6 +0, 131, 131, 1, 3110400, a99b759bdfcf7f7cee8f1ee84ca2d66d +1, 209920, 209920, 1024, 4096, e1b2afbfcb5edb8e4b88ae9c08848c30 +1, 210944, 210944, 1024, 4096, 58c8914fd4ec12bfe13f388050b251e8 +0, 132, 132, 1, 3110400, 5439cd9643a76d21e5f1deb0aa4000a2 +1, 211968, 211968, 1024, 4096, 4d8e0b0d4cd31f98eb4ca9922bba1497 +1, 212992, 212992, 1024, 4096, 02b1c362c2f1939fa41a4cc8d4b25d6a +0, 133, 133, 1, 3110400, 383640e375fa6b46bba21acd556f0efd +1, 214016, 214016, 1024, 4096, 10d3b076171713e9978c67515fdd4304 +0, 134, 134, 1, 3110400, e91ba9ef2595fbee20fb0f1d5e0b92ba +1, 215040, 215040, 1024, 4096, 726450c85dbd838bc00c6866d4c10786 +1, 216064, 216064, 1024, 4096, 3479045f30a97faaed2f241478ea0447 +0, 135, 135, 1, 3110400, 9c8ce07f22215b8450b01e82fc085b3d +1, 217088, 217088, 1024, 4096, 63d5ca0f8d7e086dfae54e86a75f8971 +0, 136, 136, 1, 3110400, 4f11b553eaaa1feb682842a1123e1b43 +1, 218112, 218112, 1024, 4096, 41953b97d8f2d3e5c05827c670e3c562 +1, 219136, 219136, 1024, 4096, 50709f01bf8dbe8e40f5b414211e7dbe +0, 137, 137, 1, 3110400, 32e8823643ce4cb0154482611f4de51d +1, 220160, 220160, 1024, 4096, 03d813116d70fed14987e17ebcaeed3e +0, 138, 138, 1, 3110400, 207ee505f0cfb54a3fd1fd5256ba906a +1, 221184, 221184, 1024, 4096, d695e2905aac1dee39a8f35e3a4b7fed +1, 222208, 222208, 1024, 4096, 35c5c7a9cfe5cfb08d3dd269aec9b901 +0, 139, 139, 1, 3110400, f95de0e1f3cd2559b6a81a6dbe53ed5c +1, 223232, 223232, 1024, 4096, 2a4f3699775e0d67651c4c40913c9059 +0, 140, 140, 1, 3110400, 3c47b1ea481bdae7b7730084407fd22a +1, 224256, 224256, 1024, 4096, bb561814ffb5b76a1faf7df4375c233e +1, 225280, 225280, 1024, 4096, a3c632a0d54e07e3928aec8ef169fd11 +0, 141, 141, 1, 3110400, fbec533f0cb4d79185e09c9917329473 +1, 226304, 226304, 1024, 4096, a805c35e91615f17669130ec58191b75 +1, 227328, 227328, 1024, 4096, 0858806663f6430219b68df7ff83a932 +0, 142, 142, 1, 3110400, 5b9f1cf510bc72d42772a78d400d9831 +1, 228352, 228352, 1024, 4096, 59339810dea47a705ab9e0913f7a88d5 +0, 143, 143, 1, 3110400, 6b031f180439e753b6b0e36de46dc1a5 +1, 229376, 229376, 1024, 4096, 6d9cdd81e0ba85ad4e00c34e2a096611 +1, 230400, 230400, 1024, 4096, cd6dd8dd0dc5198b7bf0b45d4ecc2608 +0, 144, 144, 1, 3110400, c09870b1e13efa8b685d89ebd781e835 +1, 231424, 231424, 1024, 4096, c2dd972eb34af27a210bcfa3e5f8da93 +0, 145, 145, 1, 3110400, 439c6cc6f7157eaf046e06d9e55ddf69 +1, 232448, 232448, 1024, 4096, 0993bc45c9582048d6982beeaec6b72e +1, 233472, 233472, 1024, 4096, ae93c593fd775ae997c43eef40fe8d0e +0, 146, 146, 1, 3110400, 7d5520c184c7bf3f175eea3526deb7a8 diff --git a/tests/ref/fate/mov-elst-ends-betn-b-and-i b/tests/ref/fate/mov-elst-ends-betn-b-and-i new file mode 100644 index 000000000..d6f325bba --- /dev/null +++ b/tests/ref/fate/mov-elst-ends-betn-b-and-i @@ -0,0 +1,33 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 115200, e10741e5457e9326d5e992e6c05c3e32 +0, 1, 1, 1, 115200, 7e20f8729b6b53dc11791927bf4a5aec +0, 2, 2, 1, 115200, 4e5dc2b806e394cd666c968f736fecd0 +0, 3, 3, 1, 115200, 7a3c7473d44c5f60c07655f6fc0c2ac3 +0, 4, 4, 1, 115200, 038254422a603a3270c09cdcd149707b +0, 5, 5, 1, 115200, 7553b6b4547cb23ef8f0392ed5a5d4b0 +0, 6, 6, 1, 115200, 6d017ede7f446124af7308667cb0dc41 +0, 7, 7, 1, 115200, 77752f0288ae64f857732b8e62e47457 +0, 8, 8, 1, 115200, d656833951af99330625f7c6de7685c4 +0, 9, 9, 1, 115200, 14338b833e431e566ac98da841600bfe +0, 10, 10, 1, 115200, 07ea95d1659f3c4424a470a546d0df6e +0, 11, 11, 1, 115200, fd05b8cc83072f813e89d394d1f6efc6 +0, 12, 12, 1, 115200, 750b82ca5c7e901545e7b1aa69692426 +0, 13, 13, 1, 115200, 7347679ab09bc936047368b8caebcaff +0, 14, 14, 1, 115200, 63a23fdd57ac8462b9ffbcb12ab717b3 +0, 15, 15, 1, 115200, 705257a1c99693db233e2a3ee027adcf +0, 16, 16, 1, 115200, df861a2ec7a4ef70e82b1c28025e5a48 +0, 17, 17, 1, 115200, 2a8b403c077b6b43aa71eaf7d1537713 +0, 18, 18, 1, 115200, 973b5cd3ce473e3970dfa96045553172 +0, 19, 19, 1, 115200, fc612c0afeae3b6576b5ee2f3f119832 +0, 20, 20, 1, 115200, 97074fe5a0b6e7e8470729654092e56c +0, 21, 21, 1, 115200, 8cf9337201065335b3aa4da21dc9b37a +0, 22, 22, 1, 115200, 93ff3589294cc0673af3daee1e7fe42a +0, 23, 23, 1, 115200, c0b6fd870a022f374f9d6c697e8e293d diff --git a/tests/ref/fate/mov-frag-overlap b/tests/ref/fate/mov-frag-overlap new file mode 100644 index 000000000..265a93d7e --- /dev/null +++ b/tests/ref/fate/mov-frag-overlap @@ -0,0 +1,105 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1001/24000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 640x360 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 345600, bb5e1ec37e1cb5a4ef2399c7b1c0ed08 +0, 1, 1, 1, 345600, 40455fa94b1f3b1cd199f127401fe187 +0, 2, 2, 1, 345600, 9147b59915250de3508f062b45dda499 +0, 3, 3, 1, 345600, bb9b9109ea61622f491c1e2aa21c503e +0, 4, 4, 1, 345600, eaceff4d694212b2eb6abf5e090d7b4c +0, 5, 5, 1, 345600, eaceff4d694212b2eb6abf5e090d7b4c +0, 6, 6, 1, 345600, f04ca4f64e7e990874c7ac9264ebbe65 +0, 7, 7, 1, 345600, f195d115e0ad6d5c240b08226d312cef +0, 8, 8, 1, 345600, 7585f3f325cc82028701fcd2360610e0 +0, 9, 9, 1, 345600, 7585f3f325cc82028701fcd2360610e0 +0, 10, 10, 1, 345600, 4e4a2d2d47881b238c4f423917c29182 +0, 11, 11, 1, 345600, 72609b459bde5644fe5815bb88fa537e +0, 12, 12, 1, 345600, 67569df185a64ec08498d71e94ab0197 +0, 13, 13, 1, 345600, 352e1d41fd8d5fb0a92b722782591066 +0, 14, 14, 1, 345600, f50f96f0ff0ee58ef8577cb9ce218be4 +0, 15, 15, 1, 345600, 9681c998992d20055388ae6c0d4f40e6 +0, 16, 16, 1, 345600, 4cd9c3056c0d1b2d6ed666d2fbabef45 +0, 17, 17, 1, 345600, 88d0c13cff5acb1746e7bb227e7ec81a +0, 18, 18, 1, 345600, 37a15a2d1d055a9c157a82d77cf48328 +0, 19, 19, 1, 345600, f30e43818a41242ca75caec4be7f366d +0, 20, 20, 1, 345600, e0441ca5e4137910ed94ea2d67f506ad +0, 21, 21, 1, 345600, 61cae30cdb5512610ba1ffb7b372be51 +0, 22, 22, 1, 345600, 28832e6ec917fece50ab94f8d6883d4b +0, 23, 23, 1, 345600, 07cfd60c53a4ede0de4f5eba749abae0 +0, 24, 24, 1, 345600, 254b072e2fe7017933738b8d43cd3f2e +0, 25, 25, 1, 345600, aa2ceef866576011653fc9e4add8c852 +0, 26, 26, 1, 345600, d5507e992763f69ef7da06bca2e5e0e4 +0, 27, 27, 1, 345600, 3d7fd83fab12dc9ca1bb5c0d09104174 +0, 28, 28, 1, 345600, 1fdc34d30f94bfa2acd5ab4791b3b6be +0, 29, 29, 1, 345600, a993a348279f71db20e48a879c718096 +0, 30, 30, 1, 345600, b999b6a51b3bdeb99df80aa88f2c43ff +0, 31, 31, 1, 345600, 2c851f444aaf1dd6f149ee8e6e1bdfa4 +0, 32, 32, 1, 345600, a50301d48d283e9881d142cd87128d86 +0, 33, 33, 1, 345600, 0ddffa560c6310a2ad1cb534336472ac +0, 34, 34, 1, 345600, 5f5565daeb737f3543a5d07ff9115d4a +0, 35, 35, 1, 345600, 91640f9887d074221e4e08f9a97a938b +0, 36, 36, 1, 345600, bc01f13d5c73a92895ca2ad13209628a +0, 37, 37, 1, 345600, 9750f282817c6df143565e2f57f9f85f +0, 38, 38, 1, 345600, a1803a3ce342d25b45f913cc8b9fe961 +0, 39, 39, 1, 345600, 4a0ae00d4e9df52c7df5bfb08236ae96 +0, 40, 40, 1, 345600, 819b12f2f7356b296bffd39e85c9b6be +0, 41, 41, 1, 345600, 40a5af89bff4b10a10d0a51ab5eeb4e0 +0, 42, 42, 1, 345600, 454a9b71be88d3c026cb7239988f3e37 +0, 43, 43, 1, 345600, c653e9c9d64c9495b764b0a6eb3bfbc9 +0, 44, 44, 1, 345600, 6a4facbf8e14ff6177fd4b0f6f659180 +0, 45, 45, 1, 345600, 843d5b77042e347c3d21d113ba2993fb +0, 46, 46, 1, 345600, 284785e924efba8ab17e6e1f75329287 +0, 47, 47, 1, 345600, 4f2b2d0f3dc4ad165e0bc56560930d49 +0, 48, 48, 1, 345600, 71154e17c2f5c316272e8904ef61c0bc +0, 49, 49, 1, 345600, 6b10588be4540b5dbbd765db406b8723 +0, 50, 50, 1, 345600, aaf62a95b621c8de2dca22f78594b8c7 +0, 51, 51, 1, 345600, bb508b634416287baf4406f70ca3693d +0, 52, 52, 1, 345600, 0551149846fca1ae1d164a7a7c64439f +0, 53, 53, 1, 345600, c3fad13ac1643744c4ea194763ae6cf7 +0, 54, 54, 1, 345600, 4c487adf3ec204c041a50cbf82abd8e8 +0, 55, 55, 1, 345600, dc48539225f4dc05588995d4288c71d0 +0, 56, 56, 1, 345600, be005c4f81422a775fc909dcee84094d +0, 57, 57, 1, 345600, a374c2ed0e644f03cbb8cd5456877cbb +0, 58, 58, 1, 345600, 9b7d5fac577cf0d82e11551cd9b280db +0, 59, 59, 1, 345600, c1d0551bc5cd1f53133e30ed811d8032 +0, 60, 60, 1, 345600, 6ab563cf2df92a2e9e1b8b90c0e0ec07 +0, 61, 61, 1, 345600, 19dadbe3c3638578fe8a3ed3f730858e +0, 62, 62, 1, 345600, e9810a12f7c14c4b8305a418e4bc3055 +0, 63, 63, 1, 345600, d45d74535cd471949238716bdc12c16f +0, 64, 64, 1, 345600, d1c2c19d0aba4170fe1a03f9c10b6863 +0, 65, 65, 1, 345600, 047c7fbfcce41fcaec6f1e1686db0429 +0, 66, 66, 1, 345600, 4adc1aa1017880f6baf4786ecd2c8ddb +0, 67, 67, 1, 345600, 90bad80d9e6c75784423f74984e40dd2 +0, 68, 68, 1, 345600, feb378d740e1e5f9312bf68c047040c3 +0, 69, 69, 1, 345600, 28b1de125fd6f6a9d42eb42300be7a3f +0, 70, 70, 1, 345600, 495043e65515c790c1fe026c9d2c0a49 +0, 71, 71, 1, 345600, fa6d5062932e7fc11fbfe31349ecbbfd +0, 72, 72, 1, 345600, 897952d332218f2dab7d760b2d2076eb +0, 73, 73, 1, 345600, 79dfce7ac29b96ef23c7f648e87a3e0b +0, 74, 74, 1, 345600, 94d11a85dc32b4693048a39a6227919b +0, 75, 75, 1, 345600, f9c149dbdc71c60f146cf68a673102d5 +0, 76, 76, 1, 345600, febddbb90b3f37cb29b07102575d844f +0, 77, 77, 1, 345600, b9e5cdfa63c2637f2204dcb885608bb9 +0, 78, 78, 1, 345600, 051773f40a3749b54c5a802f8a97128f +0, 79, 79, 1, 345600, 5fed52a298b8eef94ebe21c03313a5d7 +0, 80, 80, 1, 345600, f8a447cd738ec587fbacde061db51be5 +0, 81, 81, 1, 345600, 474cfd0529c0a5daffdcaed5183ee583 +0, 82, 82, 1, 345600, b0dd2ddd7037e70e774a7b3baad0b094 +0, 83, 83, 1, 345600, 86622696017283d3ce98e71d10f89f75 +0, 84, 84, 1, 345600, 20d6ae8b4dcf75ab31cc1f00002298ca +0, 85, 85, 1, 345600, a882528cd387fb3a55d6e184a33fe2c9 +0, 86, 86, 1, 345600, 6bfcb539ce16f3db0d7f24dab6166913 +0, 87, 87, 1, 345600, 6bfcb539ce16f3db0d7f24dab6166913 +0, 88, 88, 1, 345600, 3bde52ee85883e4f353d4736a47b3874 +0, 89, 89, 1, 345600, 6f20835eb29f824d6a3e1be0ce772f08 +0, 90, 90, 1, 345600, 7b99b15c1b8fbe0e643b75fda7b17b04 +0, 91, 91, 1, 345600, f0139cd28a0030d611d60e9d28837af0 +0, 92, 92, 1, 345600, f0139cd28a0030d611d60e9d28837af0 +0, 93, 93, 1, 345600, adf0a37ad23c38b54c7394871c876468 +0, 94, 94, 1, 345600, f0bd37bcb8299e90efd05a0e01c84029 +0, 95, 95, 1, 345600, 8a9d76bc611731eabc29bbf231e21528 diff --git a/tests/ref/fate/mov-guess-delay-1 b/tests/ref/fate/mov-guess-delay-1 new file mode 100644 index 000000000..96cb67be0 --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-1 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=1 +[/STREAM] diff --git a/tests/ref/fate/mov-guess-delay-2 b/tests/ref/fate/mov-guess-delay-2 new file mode 100644 index 000000000..248de1c3e --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-2 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=2 +[/STREAM] diff --git a/tests/ref/fate/mov-guess-delay-3 b/tests/ref/fate/mov-guess-delay-3 new file mode 100644 index 000000000..248de1c3e --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-3 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=2 +[/STREAM] diff --git a/tests/ref/fate/mov-ibi-elst-starts-b b/tests/ref/fate/mov-ibi-elst-starts-b new file mode 100644 index 000000000..1ab9c2a51 --- /dev/null +++ b/tests/ref/fate/mov-ibi-elst-starts-b @@ -0,0 +1,33 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 115200, 7e20f8729b6b53dc11791927bf4a5aec +0, 1, 1, 1, 115200, 4e5dc2b806e394cd666c968f736fecd0 +0, 2, 2, 1, 115200, 7a3c7473d44c5f60c07655f6fc0c2ac3 +0, 3, 3, 1, 115200, 038254422a603a3270c09cdcd149707b +0, 4, 4, 1, 115200, 7553b6b4547cb23ef8f0392ed5a5d4b0 +0, 5, 5, 1, 115200, 6d017ede7f446124af7308667cb0dc41 +0, 6, 6, 1, 115200, 77752f0288ae64f857732b8e62e47457 +0, 7, 7, 1, 115200, d656833951af99330625f7c6de7685c4 +0, 8, 8, 1, 115200, 14338b833e431e566ac98da841600bfe +0, 9, 9, 1, 115200, 07ea95d1659f3c4424a470a546d0df6e +0, 10, 10, 1, 115200, fd05b8cc83072f813e89d394d1f6efc6 +0, 11, 11, 1, 115200, 750b82ca5c7e901545e7b1aa69692426 +0, 12, 12, 1, 115200, 7347679ab09bc936047368b8caebcaff +0, 13, 13, 1, 115200, 63a23fdd57ac8462b9ffbcb12ab717b3 +0, 14, 14, 1, 115200, 705257a1c99693db233e2a3ee027adcf +0, 15, 15, 1, 115200, df861a2ec7a4ef70e82b1c28025e5a48 +0, 16, 16, 1, 115200, 2a8b403c077b6b43aa71eaf7d1537713 +0, 17, 17, 1, 115200, 973b5cd3ce473e3970dfa96045553172 +0, 18, 18, 1, 115200, fc612c0afeae3b6576b5ee2f3f119832 +0, 19, 19, 1, 115200, 97074fe5a0b6e7e8470729654092e56c +0, 20, 20, 1, 115200, 8cf9337201065335b3aa4da21dc9b37a +0, 21, 21, 1, 115200, 93ff3589294cc0673af3daee1e7fe42a +0, 22, 22, 1, 115200, c0b6fd870a022f374f9d6c697e8e293d +0, 23, 23, 1, 115200, bc4638ff7036b323c39a948a6407695d diff --git a/tests/ref/fate/mov-invalid-elst-entry-count b/tests/ref/fate/mov-invalid-elst-entry-count new file mode 100644 index 000000000..ac1e02ea0 --- /dev/null +++ b/tests/ref/fate/mov-invalid-elst-entry-count @@ -0,0 +1,57 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/24 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 640x480 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 460800, 549730883a0b56e6accaf021903daecf +0, 1, 1, 1, 460800, d5fc844d512a1decb0814b8692914d60 +0, 2, 2, 1, 460800, 69753185911f99aa38bd9d9ee0ff24f7 +0, 3, 3, 1, 460800, 2a985178c8b24e97708c6d33142f18a9 +0, 4, 4, 1, 460800, a23818e43bdf4ee77291e0f74051d0bf +0, 5, 5, 1, 460800, f2c927b11350b9822065bec5f06b65d9 +0, 6, 6, 1, 460800, 0c553fb530cf042eb84f5b13817a96a6 +0, 7, 7, 1, 460800, a2be429b570ce30a7471b901f2ea5bcc +0, 8, 8, 1, 460800, b4f4a3b1988404b35c57688755beb8b9 +0, 9, 9, 1, 460800, 2778b931d5e1570e1b809a87b1c45491 +0, 10, 10, 1, 460800, 4eb341ebf32006d8bce13f1d132d84b2 +0, 11, 11, 1, 460800, c39a34287300ee52547752198a2222fc +0, 12, 12, 1, 460800, f3ec59e6fc4e3c2e75f42bef34ca73b5 +0, 13, 13, 1, 460800, 3f0e6116a94fefe890b79d1e94c156c6 +0, 14, 14, 1, 460800, 0a8a597c0806818112bf8351f53d350a +0, 15, 15, 1, 460800, ab5c10023712ea21d595f5f856f53c66 +0, 16, 16, 1, 460800, d4e218051ef32e68e3df58c8c3d6a1ab +0, 17, 17, 1, 460800, 24082fa9a277123a65398a36cb1b06af +0, 18, 18, 1, 460800, 4c6da38c984496fb514d5e4d8ebb13f8 +0, 19, 19, 1, 460800, 5354435f662e80a47e1460d3ba020133 +0, 20, 20, 1, 460800, 6854beaaf90ad9f055af80fc75e802ae +0, 21, 21, 1, 460800, cb40c57f9b61788fb4abe674b585142f +0, 22, 22, 1, 460800, 8f42c6553c33dc049f6fb5e71f631125 +0, 23, 23, 1, 460800, d393b3efa7921caab3504044551bf6c3 +0, 24, 24, 1, 460800, 60a099be31244b2f69ca6107cdbd7e06 +0, 25, 25, 1, 460800, 05e542c105dc3f6f810d815fbf022afe +0, 26, 26, 1, 460800, bf478f55694eda43942a343e0b70eb19 +0, 27, 27, 1, 460800, b1012ea5ff7232da20d2c7f242540bda +0, 28, 28, 1, 460800, 936cdd0fd147f9c3ad4e82bed77a6d2c +0, 29, 29, 1, 460800, 20baafde1ab281444d8cbf58995344c2 +0, 30, 30, 1, 460800, b0bb3647ec88d1a862e2e92c32d95b65 +0, 31, 31, 1, 460800, c86d78b06c281a8c3b63b4d7beeb3ddd +0, 32, 32, 1, 460800, 4d699157c55ec3439390c6ff400655b4 +0, 33, 33, 1, 460800, 3327b0e09944dc13f0f2124cdfad86e9 +0, 34, 34, 1, 460800, 5db56bb14cd478f70bb5244781f1382d +0, 35, 35, 1, 460800, cb8564d7a763444cc85512df3f7f10db +0, 36, 36, 1, 460800, 1256eac030985c04c4501ad5a72e9d66 +0, 37, 37, 1, 460800, 20efdff9919faac5528cb576a21d6c2a +0, 38, 38, 1, 460800, 28420714ad1008772ce8100d917e2226 +0, 39, 39, 1, 460800, 6c18dad0a470e8c0d62413b549e0ae2c +0, 40, 40, 1, 460800, 3d8b9352e5d21697733e5fb5fdd55d58 +0, 41, 41, 1, 460800, 025e32ced915530eb814d399a8b28a20 +0, 42, 42, 1, 460800, cc880a64b66f158595521182a1db8a36 +0, 43, 43, 1, 460800, 322a2349a08e3b3cd18562050287c133 +0, 44, 44, 1, 460800, c19c16a382449594f1dec7a77a4e264e +0, 45, 45, 1, 460800, 0d424b26031fa1db52fbd80c100e27a4 +0, 46, 46, 1, 460800, cef6158cd43beee0aea777982613e493 +0, 47, 47, 1, 460800, eb64a091a54ebb1077c667e1b33add2a diff --git a/tests/ref/fate/mov-zombie b/tests/ref/fate/mov-zombie index e89abb116..fef2adc35 100644 --- a/tests/ref/fate/mov-zombie +++ b/tests/ref/fate/mov-zombie @@ -1,6 +1,6 @@ packet|codec_type=video|stream_index=0|pts=0|pts_time=0.000000|dts=-3004|dts_time=-0.033378|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=4133|pos=11309|flags=K_ -frame|media_type=video|stream_index=0|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=-3004|pkt_dts_time=-0.033378|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=11309|pkt_size=4133|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=5440|pts_time=0.060444|dts=-567|dts_time=-0.006300|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=1077|pos=15442|flags=__ +frame|media_type=video|stream_index=0|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=-567|pkt_dts_time=-0.006300|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=11309|pkt_size=4133|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=2437|pts_time=0.027078|dts=2436|dts_time=0.027067|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=355|pos=16519|flags=__ frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=2437|pkt_pts_time=0.027078|pkt_dts=2436|pkt_dts_time=0.027067|best_effort_timestamp=2437|best_effort_timestamp_time=0.027078|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=16519|pkt_size=355|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=B|coded_picture_number=2|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=11446|pts_time=0.127178|dts=5439|dts_time=0.060433|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=1110|pos=16874|flags=__ @@ -129,5 +129,5 @@ packet|codec_type=video|stream_index=0|pts=188623|pts_time=2.095811|dts=188622|d frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=188623|pkt_pts_time=2.095811|pkt_dts=188622|pkt_dts_time=2.095800|best_effort_timestamp=188623|best_effort_timestamp_time=2.095811|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=100846|pkt_size=974|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=B|coded_picture_number=64|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=197632|pts_time=2.195911|dts=191625|dts_time=2.129167|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=580|pos=101820|flags=__ frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=191626|pkt_pts_time=2.129178|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=191626|best_effort_timestamp_time=2.129178|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=99180|pkt_size=1666|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=P|coded_picture_number=63|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft -stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_time_base=212521/12744000|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|has_b_frames=0|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=unknown|timecode=N/A|refs=2|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|tag:rotate=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Alias Data Handler|tag:encoder=H.264 +stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_time_base=212521/12744000|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|has_b_frames=1|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=unknown|timecode=N/A|refs=2|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|tag:rotate=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Alias Data Handler|tag:encoder=H.264 side_data|side_data_type=Display Matrix|displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|rotation=0 diff --git a/tests/ref/fate/mpeg2-ticket6677 b/tests/ref/fate/mpeg2-ticket6677 new file mode 100644 index 000000000..5fc7cb2a2 --- /dev/null +++ b/tests/ref/fate/mpeg2-ticket6677 @@ -0,0 +1,12 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 8/9 +0, 0, 0, 1, 518400, 0x354b6fc3 +0, 1, 1, 1, 518400, 0xd86f281b +0, 2, 2, 1, 518400, 0xdd2e2b38 +0, 3, 3, 1, 518400, 0x589535d4 +0, 4, 4, 1, 518400, 0x3f8f02b6 +0, 5, 5, 1, 518400, 0xa81b246a +0, 6, 6, 1, 518400, 0xb98dd9f7 diff --git a/tests/ref/fate/mxf-reel_name b/tests/ref/fate/mxf-reel_name new file mode 100644 index 000000000..fb9586097 --- /dev/null +++ b/tests/ref/fate/mxf-reel_name @@ -0,0 +1 @@ +dda6c54b642b8794a87d809fdb361f95 diff --git a/tests/ref/fate/rgb24-mkv b/tests/ref/fate/rgb24-mkv index 4c357acca..439b2bc5e 100644 --- a/tests/ref/fate/rgb24-mkv +++ b/tests/ref/fate/rgb24-mkv @@ -1,5 +1,5 @@ -55270be3b5d393d770a1dfcb19b68271 *tests/data/fate/rgb24-mkv.matroska -58345 tests/data/fate/rgb24-mkv.matroska +09ee413b2d92a6be5e3b18e9e20a1f74 *tests/data/fate/rgb24-mkv.matroska +58342 tests/data/fate/rgb24-mkv.matroska #tb 0: 1/10 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/sub-cc-scte20 b/tests/ref/fate/sub-cc-scte20 new file mode 100644 index 000000000..71fc92bfc --- /dev/null +++ b/tests/ref/fate/sub-cc-scte20 @@ -0,0 +1,15 @@ +[Script Info] +; Script generated by FFmpeg/Lavc +ScriptType: v4.00+ +PlayResX: 384 +PlayResY: 288 + +[V4+ Styles] +Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding +Style: Default,Monospace,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,3,1,0,2,10,10,10,0 + +[Events] +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text +Dialogue: 0,0:00:00.00,0:00:01.44,Default,,0,0,0,,{\an7}{\pos(48,182)}BESIDES THE +Dialogue: 0,0:00:01.43,0:00:03.93,Default,,0,0,0,,{\an7}{\pos(38,166)}\hBESIDES THE \N{\an7}{\pos(38,197)}SPENDING AND THIS, IS THAT CAR +Dialogue: 0,0:00:03.94,0:00:06.31,Default,,0,0,0,,{\an7}{\pos(38,182)}SPENDING AND THIS, IS THAT CAR \N{\an7}{\pos(38,197)}MANUFACTURERS ARE ABOUT AS diff --git a/tests/ref/fate/time_base b/tests/ref/fate/time_base index 7923556b3..4dd14084d 100644 --- a/tests/ref/fate/time_base +++ b/tests/ref/fate/time_base @@ -1 +1 @@ -d26a35b141551b36c5b8bd716451cfcb +f97551f884df5ab709c5869c66c7b9bc diff --git a/tests/ref/fate/utvideo_rgb_int_gradient b/tests/ref/fate/utvideo_rgb_int_gradient new file mode 100644 index 000000000..a4e698662 --- /dev/null +++ b/tests/ref/fate/utvideo_rgb_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xd00fdd8c diff --git a/tests/ref/fate/utvideo_rgb_int_median b/tests/ref/fate/utvideo_rgb_int_median new file mode 100644 index 000000000..a4e698662 --- /dev/null +++ b/tests/ref/fate/utvideo_rgb_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xd00fdd8c diff --git a/tests/ref/fate/utvideo_rgba_gradient b/tests/ref/fate/utvideo_rgba_gradient new file mode 100644 index 000000000..f52f46b23 --- /dev/null +++ b/tests/ref/fate/utvideo_rgba_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 37x37 +#sar 0: 0/1 +0, 0, 0, 1, 5476, 0x20f860ad diff --git a/tests/ref/fate/utvideo_yuv420_gradient b/tests/ref/fate/utvideo_yuv420_gradient new file mode 100644 index 000000000..5e2b7ee1b --- /dev/null +++ b/tests/ref/fate/utvideo_yuv420_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 4608, 0xc441dd90 diff --git a/tests/ref/fate/utvideo_yuv420_int_gradient b/tests/ref/fate/utvideo_yuv420_int_gradient new file mode 100644 index 000000000..08e45d79e --- /dev/null +++ b/tests/ref/fate/utvideo_yuv420_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 4608, 0x8cecddae diff --git a/tests/ref/fate/utvideo_yuv420_int_median b/tests/ref/fate/utvideo_yuv420_int_median new file mode 100644 index 000000000..08e45d79e --- /dev/null +++ b/tests/ref/fate/utvideo_yuv420_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 4608, 0x8cecddae diff --git a/tests/ref/fate/utvideo_yuv422_gradient b/tests/ref/fate/utvideo_yuv422_gradient new file mode 100644 index 000000000..f4949b234 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv422_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 6144, 0xd33add91 diff --git a/tests/ref/fate/utvideo_yuv422_int_gradient b/tests/ref/fate/utvideo_yuv422_int_gradient new file mode 100644 index 000000000..f4949b234 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv422_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 6144, 0xd33add91 diff --git a/tests/ref/fate/utvideo_yuv422_int_median b/tests/ref/fate/utvideo_yuv422_int_median new file mode 100644 index 000000000..f4949b234 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv422_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 6144, 0xd33add91 diff --git a/tests/ref/fate/utvideo_yuv444_709_gradient b/tests/ref/fate/utvideo_yuv444_709_gradient new file mode 100644 index 000000000..0870c87d3 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 38x38 +#sar 0: 0/1 +0, 0, 0, 1, 4332, 0xa9de65ba diff --git a/tests/ref/fate/utvideo_yuv444_709_int_gradient b/tests/ref/fate/utvideo_yuv444_709_int_gradient new file mode 100644 index 000000000..af9337cd6 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xbcb2dd78 diff --git a/tests/ref/fate/utvideo_yuv444_709_int_median b/tests/ref/fate/utvideo_yuv444_709_int_median new file mode 100644 index 000000000..af9337cd6 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xbcb2dd78 diff --git a/tests/ref/fate/utvideo_yuv444_709_median b/tests/ref/fate/utvideo_yuv444_709_median new file mode 100644 index 000000000..af9337cd6 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xbcb2dd78 diff --git a/tests/ref/fate/utvideoenc_rgb_left b/tests/ref/fate/utvideoenc_rgb_left index a1d200096..1ee7c5856 100644 --- a/tests/ref/fate/utvideoenc_rgb_left +++ b/tests/ref/fate/utvideoenc_rgb_left @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 182328, cd084b244939d7e0008d8e5ab3429dc1 -0, 1, 1, 1, 182336, c9c40672750f372134185901147fb776 -0, 2, 2, 1, 182956, c728911ca73225f2dc7453533c9be95e -0, 3, 3, 1, 182384, 54521f709b461a25198db755bce582fa -0, 4, 4, 1, 181704, 5e03ab58b4480a6613f54857f10c39e5 -0, 5, 5, 1, 182136, c623fb06b90fdd7a5ba0b4f217b6a388 -0, 6, 6, 1, 181552, 5d03be9dfc01ad99364fc3cc8378af72 -0, 7, 7, 1, 182292, fc90878278c82b2f835151dc6d43dd47 -0, 8, 8, 1, 181424, 9b6339a0d3af2d3034162183cd4d79e4 -0, 9, 9, 1, 182316, 7e45bb5ffe57f98a433420abaffe78cc -0, 10, 10, 1, 182064, d9525605a7d7d75a8e33502f61733af1 -0, 11, 11, 1, 182596, 62e87fa5c33a8d208deaa8719682b9a5 -0, 12, 12, 1, 180900, 149059d3d56c55358c7044c7d569730f -0, 13, 13, 1, 181920, 0d20f588c27471a038e159a131e9c8ea -0, 14, 14, 1, 182824, a301a411ff11042ecb583e1e3b12dbda -0, 15, 15, 1, 182452, 0ee2a9ed39fb8569a8d6c2b3afb8f80a -0, 16, 16, 1, 182312, 68dd3b820adf2cbc6686a7d48fa22c6e -0, 17, 17, 1, 181856, 1897926cfe9b7acaf9c21714c449ce41 -0, 18, 18, 1, 181108, 15d2af460733fdd896078632cdfef9fd -0, 19, 19, 1, 181388, 8b8e7a4b7d355f41f7e836120c4792ac -0, 20, 20, 1, 180936, e18e27aa027f2470bfa95c536a0a89af -0, 21, 21, 1, 180900, eb663ae3c5ffa8e751280e0dbb260e02 -0, 22, 22, 1, 181936, 7514bbe06cee027f54710dc900297863 -0, 23, 23, 1, 182304, 8cb2dcdbd4c919b4c977f45bee46c54c -0, 24, 24, 1, 182580, 9185ed53b7e8339b61d3abe230bbab71 -0, 25, 25, 1, 182572, 81f8bdd3255b91d6621e9ebd3c9d7679 -0, 26, 26, 1, 182356, 1f9ff40700881054c62e33acde06910d -0, 27, 27, 1, 181532, 10d2477aa1e319a61e517d25fd6c95d0 -0, 28, 28, 1, 179580, 3012480c43d15866ccc4a81d56650ee2 -0, 29, 29, 1, 179528, 5e0fbd62a164dc72cf511023da792175 -0, 30, 30, 1, 180760, 679f430c86dca203456f532e978dffc2 -0, 31, 31, 1, 181564, 64d31faf01cb7b52d7d7e20280e6652b -0, 32, 32, 1, 181428, 04961d71aa3c81b33d28b39ead20ee1d -0, 33, 33, 1, 182980, 51361c802005721002f5f4924f081708 -0, 34, 34, 1, 182624, 67c5582c45e3ee7e6aca49fdc0a980b8 -0, 35, 35, 1, 182352, 4fade9db12f2d6ce633556fdb8914971 -0, 36, 36, 1, 181336, ac8fbab67b36d58c4e8374bfb07458e7 -0, 37, 37, 1, 181528, f798157b6d4d04c767ecb76346922ddc -0, 38, 38, 1, 179776, 01d407ed0b86eeb2c3ee3c24dd452d8d -0, 39, 39, 1, 180100, 062e4af150100d7accf86a907a4b99b5 -0, 40, 40, 1, 180228, 23c617b76ef8f274bd089016fb8516c7 -0, 41, 41, 1, 180592, 5cd3d93597325196079dc019556f6933 -0, 42, 42, 1, 181188, d39d52f5b690661434b1abd8717b3e30 -0, 43, 43, 1, 181300, 9e202444287234bafd103fab83b1a974 -0, 44, 44, 1, 180812, 602165271de71594132cce98af56a7b2 -0, 45, 45, 1, 178816, c427d67196f43ece6bf3855e1256d7bb -0, 46, 46, 1, 178196, 0d05902e2870a85333a216c723077e98 -0, 47, 47, 1, 178772, 57f528eb984b5b7181c89b48b58271f3 -0, 48, 48, 1, 178652, 5cd1031b0ada3ba9c2d4c2f2b7c8e277 -0, 49, 49, 1, 178512, d3c0c84fc63f1e32a4a026e2cd39b161 +0, 0, 0, 1, 197832, 11da778d3d904fcd2ad6daf84b227e6b +0, 1, 1, 1, 197840, e89c967c27d7cd9963c9f12f9df2c268 +0, 2, 2, 1, 198632, b2c59f9834024d1e4b829e540a91814e +0, 3, 3, 1, 197100, b21b344d42da10ef6730fed553fb3f2f +0, 4, 4, 1, 196236, e61de0e4ff879b6630ae8eb63d063b7f +0, 5, 5, 1, 197352, efd21105f5f98cbd5953e85a10091531 +0, 6, 6, 1, 197252, 0e2444a9185f68294c16f034dd522666 +0, 7, 7, 1, 197204, 0254750d85c474c13fe3c0e4e3c272cf +0, 8, 8, 1, 197084, 4c89a99df233575978d9bcd8936e4588 +0, 9, 9, 1, 197692, 681a76f67892f9d05be72abaa403bc32 +0, 10, 10, 1, 197456, bba96b8520eaa5b6612b5c48d6409938 +0, 11, 11, 1, 197024, b9ea3dcc0cb8cf552e536765c5bb31f6 +0, 12, 12, 1, 195132, 2664b79397af76081b7ddd5c3507d579 +0, 13, 13, 1, 196796, d6128308c1fc3493ebc2cece7ed785cb +0, 14, 14, 1, 198708, 6b3e50d5d47f29dfb38e178ffb9036c5 +0, 15, 15, 1, 198000, a3d6be893edb02e44f65f7a06aa8eeed +0, 16, 16, 1, 197568, 1ed7a01f810770d62aed3d12d10cd12c +0, 17, 17, 1, 197396, 515e13befb9eebf92f77574d6cd9fec4 +0, 18, 18, 1, 196680, ac1835b9a426927855e3e5dbab28c177 +0, 19, 19, 1, 196784, 56fa26a339c69df17d003fb00b335baa +0, 20, 20, 1, 195980, 853744fb2a2de76858d32f35f8b3d836 +0, 21, 21, 1, 196120, e9c50124d92e261f7a98599cb9a20e36 +0, 22, 22, 1, 196620, e750eaed752d09874d823ee40a8904c4 +0, 23, 23, 1, 197528, 6671598014db402b70e2753efda028d1 +0, 24, 24, 1, 198204, 6e471eb9c354d6be4e0d8a691313e23e +0, 25, 25, 1, 197512, 7e415738fb7889dee478f63900f47e7c +0, 26, 26, 1, 196832, 0e30afab6de602d099d88edd6276f1de +0, 27, 27, 1, 196396, 13880ad888c9cf3504e2eb087767602e +0, 28, 28, 1, 194220, aa9007687cade8c9a872de063bed0755 +0, 29, 29, 1, 194428, 78ab57958ef8914095477e58ee4461c2 +0, 30, 30, 1, 195676, a7d0779dcda7f93da5601482bb68625b +0, 31, 31, 1, 196352, 668c525c910000aab7d9285be6ac7ed1 +0, 32, 32, 1, 196468, 9c124995d63f2a548e640811e9391951 +0, 33, 33, 1, 198188, 1cb600005e68d1ef1418b1b42e463f0a +0, 34, 34, 1, 197556, 80f6223aba2d6cfab3cb596f372243f2 +0, 35, 35, 1, 197020, b1890bbb734c016103190a9c043e9fe2 +0, 36, 36, 1, 196208, 7adf4b08c90231eddec16aff65cc138f +0, 37, 37, 1, 196448, de69c81a605c9e173a7ac65077d0396d +0, 38, 38, 1, 194072, 8b3afb6897210f1660b4427df0d9cc51 +0, 39, 39, 1, 194036, 1827f1deef659426939ffd94b73575bc +0, 40, 40, 1, 194436, 46f3ad01e18a2a24d720e78f9bdb532d +0, 41, 41, 1, 195696, a160ff1e281959147fe11606754ecc7d +0, 42, 42, 1, 196044, 37f15771f5c04c13b02c0127bd977fed +0, 43, 43, 1, 196384, fc43c356e577555757e220bee7e8a232 +0, 44, 44, 1, 195424, 6820346735e390b86d9564298c934101 +0, 45, 45, 1, 193688, 5f346f622f8e0d33d7f662e9dfbcccb5 +0, 46, 46, 1, 193000, 15eb6569d9fd39a343d110b965a97277 +0, 47, 47, 1, 193592, d41d561eb927b8e0d608177af90d0e1d +0, 48, 48, 1, 193512, 35112e23e238beff03c769674db40399 +0, 49, 49, 1, 192528, 3a3ac1b24fb8fc72174970d668c30292 diff --git a/tests/ref/fate/utvideoenc_rgb_median b/tests/ref/fate/utvideoenc_rgb_median index b1558d7f5..6c4d2f808 100644 --- a/tests/ref/fate/utvideoenc_rgb_median +++ b/tests/ref/fate/utvideoenc_rgb_median @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 182160, abcf4f477f74b696faca2fcff1f62aa9 -0, 1, 1, 1, 182104, 7cbcf339fa40c24522067295b39d637f -0, 2, 2, 1, 183108, dfc2c418f4379a89654c16b34ff19446 -0, 3, 3, 1, 182320, 62a4647b05709d86c51a18be16877e98 -0, 4, 4, 1, 181920, 61d63520703503f6e17fad67cbc08794 -0, 5, 5, 1, 182424, f467638396feabe613b3c851289452d8 -0, 6, 6, 1, 182248, 8a0cba950d6c5d63ba9603212ca95b0e -0, 7, 7, 1, 181876, 91432f472cf373d5d4036bd100950f3e -0, 8, 8, 1, 182104, 1c8852d82a48c1b01911ffbedf0ac1f4 -0, 9, 9, 1, 182540, f36b9d48123b55f2141ae10dd26e1ca0 -0, 10, 10, 1, 182120, e6ecdb9af6591916153ca9aeba76b9d0 -0, 11, 11, 1, 182136, 7dc7b828a5b7c652df612474fad66f6b -0, 12, 12, 1, 181296, 347eac6563435a62f75298cefe13d3a6 -0, 13, 13, 1, 182136, 3bbcd8afacdf9549da9ebd736df548a7 -0, 14, 14, 1, 182412, 17f8c6ef692b4085624ce1ef7efbc963 -0, 15, 15, 1, 182732, 9212760fa11fe4fa193ba1aa259e9765 -0, 16, 16, 1, 181944, 7dd6d6a7084f97a77ec09ec6c62f0ab8 -0, 17, 17, 1, 182232, 518552687d47ae93726679f0ed962ef4 -0, 18, 18, 1, 181512, 29a66924742add13a0cae65d93d38ea9 -0, 19, 19, 1, 181424, 67c965637248333f92da9d493bf7546e -0, 20, 20, 1, 180764, 298457c6c2b3f4ebcda87a12579f094d -0, 21, 21, 1, 181072, 493ea592b7d59eebf01c002e7e22fc43 -0, 22, 22, 1, 181160, e30195fcc16ecfbb9348943cff01623f -0, 23, 23, 1, 182156, d26cfac33e19b4ca11210c9e6cb91955 -0, 24, 24, 1, 182260, 963c157d3f0023b49d23099d53d60c8b -0, 25, 25, 1, 181976, 2494d481bf2be97692eaeda95f279b0d -0, 26, 26, 1, 181832, f1be95c840d4fcb0c8d4b7aed5b197c5 -0, 27, 27, 1, 181424, 03d92e89358a8b9b9e7cf302edde307e -0, 28, 28, 1, 180632, 09f9e162fdaf28342c442172179a75c9 -0, 29, 29, 1, 180624, 481e7f7730ab3ba67c06faa620a8bd5e -0, 30, 30, 1, 181024, 7a1d1b06b73d2bf41563eb749805780c -0, 31, 31, 1, 181844, 8a6ce6dd6f79e423a3bb6c2b163adc55 -0, 32, 32, 1, 181712, a68007bbdf0169c9ed2dffae3dc63221 -0, 33, 33, 1, 182008, f37dd0635de369761e2de979ee799c3a -0, 34, 34, 1, 181800, 14029ba1c364eca476559ce553919e99 -0, 35, 35, 1, 181840, ee227d15f15c3cd564dcad2160453fb7 -0, 36, 36, 1, 181848, 13b5d0892cc76a25b4914f2d706a0ad5 -0, 37, 37, 1, 181976, 1a0be9f2cefe0d867c5c03d6b3987ad8 -0, 38, 38, 1, 181216, 79795d735f9e0f92091203bf8b9eb9ed -0, 39, 39, 1, 181236, 2d006c8c4ba448ca7841df76e44ffa88 -0, 40, 40, 1, 180672, ed5210abdae49042fcae9bde2f65a057 -0, 41, 41, 1, 181324, fbbc7839c595cd0f0efc0917edfed2c3 -0, 42, 42, 1, 180980, c6120b5a9440f4a0d83731627eb96d98 -0, 43, 43, 1, 181204, ac4371912d16f657c90e8a00cfafdfd2 -0, 44, 44, 1, 180720, d392d95c67349296d922dbf53ec3f832 -0, 45, 45, 1, 180028, 37a2717fbd5aaeb128812298484f8267 -0, 46, 46, 1, 179704, e8716f4856e4ccdc541632a218894f62 -0, 47, 47, 1, 179648, e99cbe5d1bbd7bce241ae500b4de06c2 -0, 48, 48, 1, 179424, 6f8a5e356fb77b61d9dfcabdf97340b9 -0, 49, 49, 1, 178980, 75a7700b822236b0ecb169fd692910f1 +0, 0, 0, 1, 194232, 96431f57c15dfce7894563df186457c7 +0, 1, 1, 1, 194256, f7617d88a5bb862047dd62a3618eca2c +0, 2, 2, 1, 195048, 77aa5446e64733aa29bf5ba4ad92073d +0, 3, 3, 1, 194012, 4a73e8b156eebc15de299c57087639a5 +0, 4, 4, 1, 193268, a0afb35be4f9f91366d848b0600c949d +0, 5, 5, 1, 194168, b0580fbf05dc9a2abc053f2deb48b8c9 +0, 6, 6, 1, 194240, 5f5adb862a13843123e27f01d1870799 +0, 7, 7, 1, 193512, 71dca88d3fdf753858887006ac3cc13b +0, 8, 8, 1, 193952, 7efa7d138fa412343741ccbeb18acd18 +0, 9, 9, 1, 194700, ffddf410e5b8e49cf0462baf7bc9e179 +0, 10, 10, 1, 193984, c71b59a9699f2832e8c3d76e5d5e4f0c +0, 11, 11, 1, 193640, 598bdf3a814db44775ad703d674e9ab9 +0, 12, 12, 1, 192900, de83dd60e69a305ab0a79c4a859d444d +0, 13, 13, 1, 193780, 7858349baa970794b0353e011f751259 +0, 14, 14, 1, 194564, 9470359eb6f09d5a1db5dc199e910bcf +0, 15, 15, 1, 194856, c15823765a9d4d1583f2dd7b63534c95 +0, 16, 16, 1, 194056, 5f60ee32c9e06f080dcd0b4025576d5b +0, 17, 17, 1, 194124, a10815c6603e375ab0b21331e03651de +0, 18, 18, 1, 193508, 54a5762f2717ce1be3b9193b930d1b1f +0, 19, 19, 1, 193412, 782b07b8ac3bd1a86ad562ef7d7ebca5 +0, 20, 20, 1, 192472, 96f7f1983d6ac34c591e33045c5ba3dc +0, 21, 21, 1, 192844, b56bec01d69b3e073ac9823b2bf4c2f5 +0, 22, 22, 1, 192668, 3071c2d282672a597bee4682cef304ff +0, 23, 23, 1, 194108, 3484d2ca748c20d87280f5333054552d +0, 24, 24, 1, 194552, b05a90da02c18ee880234d620259361d +0, 25, 25, 1, 193860, 08617a493d2abe75b438a35315aef7a0 +0, 26, 26, 1, 193452, 958eaccd55d6a55832ec9cb6ce201fc4 +0, 27, 27, 1, 193364, 8cab6850866ce9c0ecf818cc4630bdb3 +0, 28, 28, 1, 192064, 03ce30fadf6b80d0b901c0f53f09e23b +0, 29, 29, 1, 192464, 7bf3364a095cbea2a032f6762d3433bf +0, 30, 30, 1, 192880, 6176bcbdf42f787aa4c21791fd3d73e2 +0, 31, 31, 1, 193672, 0760b04edf969c5b0914fcae82ee7ee3 +0, 32, 32, 1, 193636, a08c905e46e35d575001e570389a9b70 +0, 33, 33, 1, 193976, dff151dc2dfa5a86103bddc11484a38f +0, 34, 34, 1, 193456, 86f44e4a438ad150baee14facdebb701 +0, 35, 35, 1, 193768, 5645f55ed8154a0c913890a11b6f1261 +0, 36, 36, 1, 193584, 023ca364d9a88ccb2bae08008c6c3098 +0, 37, 37, 1, 193844, be83062bffff72ba0c442f502c41a187 +0, 38, 38, 1, 193008, 6e1dd8f2d18145ee199395d34c0e55ff +0, 39, 39, 1, 192680, 27256f3f1111554a75d7b7366b77457f +0, 40, 40, 1, 192188, d86ea5fafc41d57e320479f54fd1286a +0, 41, 41, 1, 193200, a37553416c0187b364ce2b64ece22975 +0, 42, 42, 1, 193052, 8e3c81d246b744c2aed9b735015ee93f +0, 43, 43, 1, 193032, dd8e2b350d8181c6a73832c868ea99f4 +0, 44, 44, 1, 192444, 6844e2dc435f417028644d3314b94c4f +0, 45, 45, 1, 191824, fc01e22ba45bca6eac69ba76043e1484 +0, 46, 46, 1, 191772, 5e2bedda3828d590d25caa14f96ba7b0 +0, 47, 47, 1, 191720, edaae522f8a975bbef0e909ef09e7fc7 +0, 48, 48, 1, 191528, f2d98179f5cf0752ecbd6d39c4457283 +0, 49, 49, 1, 190692, 74cd0f762371781712e2ff2e3f60ac57 diff --git a/tests/ref/fate/utvideoenc_rgb_none b/tests/ref/fate/utvideoenc_rgb_none index 403c807a4..27df8badc 100644 --- a/tests/ref/fate/utvideoenc_rgb_none +++ b/tests/ref/fate/utvideoenc_rgb_none @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 301024, 44de62472f485410819707c44b53f276 -0, 1, 1, 1, 301036, ff3c28c23b15834a84c57b304610924f -0, 2, 2, 1, 300812, 72f02a697464f5fdd54ae2e054c131d1 -0, 3, 3, 1, 300876, 8879becf8b3d5001b196f45b7817ef6b -0, 4, 4, 1, 300880, 2edeed55c4d84dea1fc9386553d7503f -0, 5, 5, 1, 300904, f799f26eae30e1796bd62f9cdbcb2b17 -0, 6, 6, 1, 300908, bc606ee3ab284d3567a3fbd476d674f0 -0, 7, 7, 1, 301012, 404f55be9ec860a1ab3d15711965c9ba -0, 8, 8, 1, 301048, 112394db28656101b4e8ba3621b437ae -0, 9, 9, 1, 301008, 8945bb7668b4a529844e68e1f6b6522b -0, 10, 10, 1, 300908, a9097c5f0bd7ddea711a25aa74696f70 -0, 11, 11, 1, 300876, 579de317d166295088530c78f403611d -0, 12, 12, 1, 301012, d97e3627c494012d6167a30ec8192360 -0, 13, 13, 1, 300928, fd20066b7f31363751328aefedfae04c -0, 14, 14, 1, 300836, d9bdd5606f4426b503f19a674e8058a3 -0, 15, 15, 1, 300848, 6c8f2cbd75646592876f8138a017c1ce -0, 16, 16, 1, 300988, 54e19940011b3bfed809a0edc12c3dd7 -0, 17, 17, 1, 301040, b1d5f39215f305953a846fb01dbc2f24 -0, 18, 18, 1, 301164, 9dde74f0ee3626eeea41c538fd80e1fb -0, 19, 19, 1, 301196, fdf22d2c35c7ab72416a268bf6612650 -0, 20, 20, 1, 301148, 275261bc1c1dec0bf712dcf05213def2 -0, 21, 21, 1, 301144, 66ccea6fce9d6d7016dafb3b349fa163 -0, 22, 22, 1, 301080, d6dc6ce0708dfdf74e936271a98c19e9 -0, 23, 23, 1, 301028, 48e610b9d798e0642825919fab233524 -0, 24, 24, 1, 301100, aed8f8f0a9d96ab9906ea8175e18c9ff -0, 25, 25, 1, 301116, fe9e1eccb9ccc92b4041228ea2c56c8e -0, 26, 26, 1, 301052, 3ec2f76b41fd8a6eafaa6bb14b94c153 -0, 27, 27, 1, 301200, 60d608bbe0ca285a7d8a1a4822a84c4d -0, 28, 28, 1, 301120, 6d2cec50ee32e76eb6dff76a4976d221 -0, 29, 29, 1, 301188, 8faa69fd62e0646e4eb85c1601827364 -0, 30, 30, 1, 301192, eb1fa109c5e9b89f29be7cf363649acd -0, 31, 31, 1, 301128, 32ba1797f5dee6643712688621984326 -0, 32, 32, 1, 301088, a1bfa70314c40f60a0823beef74e233e -0, 33, 33, 1, 301064, b18d84efa0091199dd9167bbdb36b873 -0, 34, 34, 1, 300964, a2ae8d3dd655403bcfdace40aaa1d78b -0, 35, 35, 1, 301124, 8ece60df0f0ef4f3d887eac16c23cad6 -0, 36, 36, 1, 301200, 13eb4b5ec7471837aadce38848e48cb2 -0, 37, 37, 1, 301196, b5fdef211755134f8e7998793a0ab0c0 -0, 38, 38, 1, 301260, 2f7e2046bae9e664e74bc56a3596743c -0, 39, 39, 1, 301264, 2cfc013c9e66a5dd0229c6551febd658 -0, 40, 40, 1, 301272, 47e8ff02a8f054c66687e2b613e46cf5 -0, 41, 41, 1, 301236, f4d766155eeeb7b03687a3141840bf32 -0, 42, 42, 1, 301312, 8fe134aefc02b6910dc2054447fd9c37 -0, 43, 43, 1, 301272, 9ec57db275fca2b596734c48a50c28bc -0, 44, 44, 1, 301256, 17bae207d8d6f5b2b500885e3058185f -0, 45, 45, 1, 301308, 9f8e91f3fbbdd0ca17b2ad0ffe888d5a -0, 46, 46, 1, 301400, 8184e55eb5432516547df512175c15fc -0, 47, 47, 1, 301408, dd0c0aa1426427549e9cbb22ef82f930 -0, 48, 48, 1, 301424, c65025dc3fa21fad98118ab0386b910e -0, 49, 49, 1, 301408, 2982b49e94aa25b8ef30f81769650f15 +0, 0, 0, 1, 303768, c37d23b5bc1dcceacafcebd0a5054590 +0, 1, 1, 1, 303764, a6a8b445323c00ab56ad1077a90b34bf +0, 2, 2, 1, 303672, 029048769e006f2a2357f373cfc0b6bf +0, 3, 3, 1, 303672, e13433d7e8f75a26eeca86523d47d0cf +0, 4, 4, 1, 303724, 4c3d437c158255e398071bdd2e699d9e +0, 5, 5, 1, 303672, 11e335df4fdfcfb7563305a33740058e +0, 6, 6, 1, 303676, 594a7a6101fbf884bb3bc309479bdf18 +0, 7, 7, 1, 303764, 09f91a05f8f507f6338d15591df34002 +0, 8, 8, 1, 303772, 1e177889c188fdd783815103c1987e5e +0, 9, 9, 1, 303700, f6da8873c69fb6365764327305a36840 +0, 10, 10, 1, 303684, 6810c80719058078b7d40a787fabee70 +0, 11, 11, 1, 303696, f8dcad694c276074f5022276e4067694 +0, 12, 12, 1, 303720, d1f764aaf14e78b64b182503342df764 +0, 13, 13, 1, 303676, 43066ddba20726f57d76230891f76730 +0, 14, 14, 1, 303548, 6512bff050521cd6343e5b2f4b18be6c +0, 15, 15, 1, 303604, 76c91368e8db8c18591c7cb569774e12 +0, 16, 16, 1, 303748, 365805842ee3cefee8d5feb169075ecf +0, 17, 17, 1, 303740, e6bbc34d7057d812cd994473b93ccadb +0, 18, 18, 1, 303788, 48bcbbc3bf805586c34ff23ebeaa28ea +0, 19, 19, 1, 303808, 29f268867c4522551e6f73dd4afb36e1 +0, 20, 20, 1, 303808, effd1cf0a61501f427e47c76c469ff32 +0, 21, 21, 1, 303832, 0ea84576612a4b0b8f9e14b3ecf10861 +0, 22, 22, 1, 303800, 4b4d24ce4f176de4c34ec85656ea1e49 +0, 23, 23, 1, 303716, 58845ad1c9a07d62f83414662eaf1181 +0, 24, 24, 1, 303780, 8db647c5324b3c061aa2cdae7527ec8d +0, 25, 25, 1, 303824, 7a2ddbe9d1af3d34d7538ba10a0aae3c +0, 26, 26, 1, 303796, a8444e8ec7b64c3481766ebcafd2e7b7 +0, 27, 27, 1, 303816, bf78e04e04429aab3527baacd51da1b0 +0, 28, 28, 1, 303872, 02d9693cc78af1b9d4a17b5361daa325 +0, 29, 29, 1, 303900, 065cde35c0ac49675a9ee8e047bb1471 +0, 30, 30, 1, 303876, 0888dd5201864a9f34f784b7959563ba +0, 31, 31, 1, 303828, 6837a1a3f4ae04c9601fa9f4c27098b2 +0, 32, 32, 1, 303720, 8c90fc8481d745b020c325134bf0047d +0, 33, 33, 1, 303704, d37bd88a42e4b84a98f0e51208a3877d +0, 34, 34, 1, 303640, 2444c069427bf6a847113fd16e7a863f +0, 35, 35, 1, 303780, 7a9aa1d7d43bcb22a754fa5e7ee911a0 +0, 36, 36, 1, 303828, 4a0ab1bbea88697950bbafe566a03b52 +0, 37, 37, 1, 303860, 6d2073d28e226286e1e78df92bc27154 +0, 38, 38, 1, 303884, 74c43f24d636de3fd6afd1d0ab098e57 +0, 39, 39, 1, 303876, 329a1d1558ffc42b7cdb1f141e042431 +0, 40, 40, 1, 303912, 6b1f3c35f28ab1182354b33ea9e37331 +0, 41, 41, 1, 303856, ec00db5b019a3f72c3fc934d3811cad7 +0, 42, 42, 1, 303880, 6d291f829145c07f0002631b0e22a1f9 +0, 43, 43, 1, 303856, c438ae4db7f897c9e2a1bc6526bb43e1 +0, 44, 44, 1, 303828, d9e5870cf4598577e4ba0ac468ef25db +0, 45, 45, 1, 303936, 6c90dbca317295010024cc4ec70d3f87 +0, 46, 46, 1, 303940, 025d9173ff307f89c3edf43074a261e9 +0, 47, 47, 1, 303948, 48e7ab65fb9c7a35e4933a7658935726 +0, 48, 48, 1, 303944, 925eb3c42b865d0861ae0348136fc18c +0, 49, 49, 1, 303924, 83ae105d9d301ea900f004d274adf894 diff --git a/tests/ref/fate/utvideoenc_rgba_left b/tests/ref/fate/utvideoenc_rgba_left index eb3305d61..11bde1e63 100644 --- a/tests/ref/fate/utvideoenc_rgba_left +++ b/tests/ref/fate/utvideoenc_rgba_left @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 195260, a8fdb226460f210542e7aca6c12b0874 -0, 1, 1, 1, 195268, 45f098764ccba85dc641b7e401461c0a -0, 2, 2, 1, 195888, e922261672c7de46a302abad3a3fe450 -0, 3, 3, 1, 195316, f8febd5af0fed000fab2943cc649975f -0, 4, 4, 1, 194636, d90985ad8afd2f969afa842510085852 -0, 5, 5, 1, 195068, 909adb44bd049186a959f2803e641520 -0, 6, 6, 1, 194484, 547772233e653daccc6610fcb6369da7 -0, 7, 7, 1, 195224, aa82b75f6230b2e948abdfe36bce1150 -0, 8, 8, 1, 194356, d67fb1208532137252701ddcbf7bfc2e -0, 9, 9, 1, 195248, 7b08698d2a911fba5231c0fef0ded4c2 -0, 10, 10, 1, 194996, 570e7d9caec52975dec1c2a5dbf7cdef -0, 11, 11, 1, 195528, 7309c0531b942902c691781f2a6da1a1 -0, 12, 12, 1, 193832, 40954ceb87370cac3db5c8c2d7c001d1 -0, 13, 13, 1, 194852, 538382c377f0c6e9070ec0b8c5fb3e39 -0, 14, 14, 1, 195756, d002a80346f3460380abb794f2d56a62 -0, 15, 15, 1, 195384, 1a4f58b3c710f2fedaf746c281556b4c -0, 16, 16, 1, 195244, 218832dab1251e1dc852e6839a48b3fc -0, 17, 17, 1, 194788, a035acf428bd9565a4c3fec25dfc6f4f -0, 18, 18, 1, 194040, 6dbfeb949bdeeb055a4f7ebf78af9a85 -0, 19, 19, 1, 194320, 8b4aa3f6f05aa684d9e4adfa4cdce814 -0, 20, 20, 1, 193868, 98cd8b150784f6695f8dea163cecf286 -0, 21, 21, 1, 193832, 27a8db33014c4bc6a8da356c4b1a3e4f -0, 22, 22, 1, 194868, f1e1460dca9127197c0a40e659924616 -0, 23, 23, 1, 195236, a012f8548e92243334edcd7c8f57aa52 -0, 24, 24, 1, 195512, bf3d4e968d126231baa6618d3344ef81 -0, 25, 25, 1, 195504, adf4b49d8721f1b323fa518f2f0d4750 -0, 26, 26, 1, 195288, aa16dd087a73a9cadc5abfc0a46ccdd4 -0, 27, 27, 1, 194464, 2e3f07244999cbe949495b57adcabe69 -0, 28, 28, 1, 192512, 2d6ce0d29a929e0208e1578e95c9d388 -0, 29, 29, 1, 192460, 081d18cd138eead0cd4b25f54a7c7540 -0, 30, 30, 1, 193692, 546b6ad28b612c2f601c7d87b265ba95 -0, 31, 31, 1, 194496, b2b2ae3b1d67e332295456e6c7bdd381 -0, 32, 32, 1, 194360, 0837b122d85abc4d704d40629266c58d -0, 33, 33, 1, 195912, b7a4bbe436d63394cee70d40e8a8a4cf -0, 34, 34, 1, 195556, 1b9a3eb6cda9bbd44bbdd0dc26a74252 -0, 35, 35, 1, 195284, f28d780d43fa6979379dd21fcb12e906 -0, 36, 36, 1, 194268, 5508989dad06fa05ee4054e759cdfd4b -0, 37, 37, 1, 194460, cb65a0e97c03b2fbe69caa6ac1660070 -0, 38, 38, 1, 192708, 4125ee86cf4b8ca6d891c176662e584f -0, 39, 39, 1, 193032, 096ee24b3e35049480e28171693fbd85 -0, 40, 40, 1, 193160, c01aef63b8bc792d08355ce6d68affee -0, 41, 41, 1, 193524, 57af47b7bfe132cf58eab2807996b3fe -0, 42, 42, 1, 194120, 9a4e2d72f4526815b253b3acce2dd49c -0, 43, 43, 1, 194232, e575508ffbd2a53871e817cd8947e2d2 -0, 44, 44, 1, 193744, 95d8eefbfbf5a7354ecbf35835243e44 -0, 45, 45, 1, 191748, de2eedebb28491e59700300635af1f90 -0, 46, 46, 1, 191128, 652670f6881419be5068f2de6ac2d91e -0, 47, 47, 1, 191704, 070f46dc278230528aa6b40256a6d891 -0, 48, 48, 1, 191584, e4b76fcf344e125729c339e360a14b15 -0, 49, 49, 1, 191444, 6a33b374a8b48549094a24543d81d999 +0, 0, 0, 1, 210764, 7c17cd8382580fcfd6dac1ddaa644c8d +0, 1, 1, 1, 210772, 4c6bcde52e58d800927620df9e0e03b8 +0, 2, 2, 1, 211564, c0754e5c821ae0c0ca0bae78ad8fe1aa +0, 3, 3, 1, 210032, 6ea988397d00f553c6e5ddbca7a08af9 +0, 4, 4, 1, 209168, c2d1fcee61bfdb5e3925aca342550ae5 +0, 5, 5, 1, 210284, dc92cc07ac1211e664a24c701c410e0e +0, 6, 6, 1, 210184, 0977e253355bff82f0efd330e94cec6c +0, 7, 7, 1, 210136, d81c28cfef7dd47abf2ac951b6a948e7 +0, 8, 8, 1, 210016, d378efd0efe103407afa8b8f45d17e24 +0, 9, 9, 1, 210624, 1a7e4a4c7b4ccbd10b9238b22dbc953b +0, 10, 10, 1, 210388, 607fdb29b0bf5846cbbb776459840401 +0, 11, 11, 1, 209956, c4c4c18b83db1983b1d9268024027025 +0, 12, 12, 1, 208064, f1a73d7fe1dfdeb33758c9d7c61fa81b +0, 13, 13, 1, 209728, ce7b81e19d940ebddeef93e281fed00d +0, 14, 14, 1, 211640, 0d6929d8d034f8accd00f58b887073f5 +0, 15, 15, 1, 210932, b895f81c00f959868e24944ee816e0df +0, 16, 16, 1, 210500, c43494420a45bb8fb0a907d3169d30b7 +0, 17, 17, 1, 210328, 5e4d72389e2733d8ce274f0c9a7cf7aa +0, 18, 18, 1, 209612, 59d368acc1ea2c0f28ed0787fe5bad4a +0, 19, 19, 1, 209716, 77a331effc0bb544ef1445fd5c42cfe2 +0, 20, 20, 1, 208912, 1de694210d8e781ce8ea29add190ad06 +0, 21, 21, 1, 209052, b48927d6e1658b5df335c34bf0fc0dc9 +0, 22, 22, 1, 209552, 1c00ad79bcf1efdb633baa040f5e1400 +0, 23, 23, 1, 210460, 755c6daf2681ba0aed4e4c962faa288c +0, 24, 24, 1, 211136, e6a5687e05a70fc7c741f2ef7afb93b9 +0, 25, 25, 1, 210444, 6fe3ec5657f092b009a7bcc4815fc5b3 +0, 26, 26, 1, 209764, 19bc9792b30711fb7276a9f74d423c3e +0, 27, 27, 1, 209328, 0144894411a4c5f14c66a393a46bb3b4 +0, 28, 28, 1, 207152, 61bbd2676caf8fbe6582274fe8add09d +0, 29, 29, 1, 207360, 9663a6d131b029c9ad7469d67a381823 +0, 30, 30, 1, 208608, a0908484dfeead74fb351bb1ba3b514a +0, 31, 31, 1, 209284, 00dda733e216eb968cfdf97f6138294d +0, 32, 32, 1, 209400, 7f7e4d3546ab89ba5eaed835a2fabf64 +0, 33, 33, 1, 211120, 3b281fadbc1eed3b4d0e6b14deb4a18f +0, 34, 34, 1, 210488, f3fb93f6504ffee9984574a7b6854d89 +0, 35, 35, 1, 209952, 1ccf5aa118c8cd51e099749289fdc374 +0, 36, 36, 1, 209140, 4e4c0f0a38608f1ff760a7ada9d44a6f +0, 37, 37, 1, 209380, dac76683c0ce9e1008fe1490dc1479bf +0, 38, 38, 1, 207004, e914b5454210fc6b4c39d22b7daf16da +0, 39, 39, 1, 206968, 0a9566c879a6897536ec094100f32fbf +0, 40, 40, 1, 207368, a644c2b3b8c89ec01b2b51576a5b09b5 +0, 41, 41, 1, 208628, 2ce6ca69d5f6e29641f5a907ffac9bb0 +0, 42, 42, 1, 208976, d3be7fe389e80df517eafd0c861947a2 +0, 43, 43, 1, 209316, c5148e0073cebd50d8f619d4875874dd +0, 44, 44, 1, 208356, 54e0082cdc1aa7fcbb8c655e94fbd410 +0, 45, 45, 1, 206620, 77ec6d3714a0dcbf0cdd5349df0951fc +0, 46, 46, 1, 205932, 7857acd2afd3169126a5428ddef97abd +0, 47, 47, 1, 206524, c903ec677106ec1f7f583bb813a1120a +0, 48, 48, 1, 206444, ea549da62a460b50811cb3f182fe5c19 +0, 49, 49, 1, 205460, 81d823633491b13a31dfdbc5f33d79f4 diff --git a/tests/ref/fate/utvideoenc_rgba_median b/tests/ref/fate/utvideoenc_rgba_median index 0cdab8d41..a2118c276 100644 --- a/tests/ref/fate/utvideoenc_rgba_median +++ b/tests/ref/fate/utvideoenc_rgba_median @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 195092, d32d5a3dc88b9aef0826b565ee5dfbc6 -0, 1, 1, 1, 195036, ea13e3522d1f3aeddd47117c91eccc55 -0, 2, 2, 1, 196040, 21c2c9abe791bed2a9bf02e539caa787 -0, 3, 3, 1, 195252, 58d5e081127f246f711f5b8ee1c760ff -0, 4, 4, 1, 194852, 8ceb3824ec628a73e1c08e498f369484 -0, 5, 5, 1, 195356, 30ea64094f29d670e2ff8f43b50578d6 -0, 6, 6, 1, 195180, 08b406b9f3063a54681d7195fb53e953 -0, 7, 7, 1, 194808, e28c43ef3aef174f0f9b9d7a702ca747 -0, 8, 8, 1, 195036, 66247b40b0def9373bf6fdda9ef832f7 -0, 9, 9, 1, 195472, efa8a624d6b0fa69e0c1c746baed0b33 -0, 10, 10, 1, 195052, fdfc784aed661cb76bc5b3ef1863bd89 -0, 11, 11, 1, 195068, 040ad503d18a36d4f1cdaec64998138a -0, 12, 12, 1, 194228, 1cd168427d022825a801b232cb23ca12 -0, 13, 13, 1, 195068, e4082f833d3bf75af24e1bb5f06d94fe -0, 14, 14, 1, 195344, 19638340e93d4f1f7099deda34d28e3f -0, 15, 15, 1, 195664, 001a801c5c5ceb197576c0f7b793850d -0, 16, 16, 1, 194876, 9550b3cf6133997bf7557483f346b036 -0, 17, 17, 1, 195164, eb7220caf48ab2605ec971ca1297a7ae -0, 18, 18, 1, 194444, a2ac812e6307a92ecd09d4282367a9d4 -0, 19, 19, 1, 194356, ee4d250226ab2a34cef0e3ed8920f7b2 -0, 20, 20, 1, 193696, 4bff0fc871969d17ad1f7391bbd543b2 -0, 21, 21, 1, 194004, 080e2a91fe768fd1725a8400bc6a1331 -0, 22, 22, 1, 194092, 5b9d65275695372e1f6b9c0a23f1ffa0 -0, 23, 23, 1, 195088, a4060bf595c877476a5952b335526d57 -0, 24, 24, 1, 195192, 17b55735834f291ecae399c317007d2c -0, 25, 25, 1, 194908, fc78d797bd5740f4fec8f3d34bc2ff1b -0, 26, 26, 1, 194764, d229a9e4d1c782504cad617d2b00802b -0, 27, 27, 1, 194356, f987a587cb9fdcd04e36d9382c4d9139 -0, 28, 28, 1, 193564, bdfa512e3a0a46aabf289c22dbaee0b9 -0, 29, 29, 1, 193556, 341708f3181ba4b37114d6dbffc65e63 -0, 30, 30, 1, 193956, f97693469ae6f49c3995794d00430c4a -0, 31, 31, 1, 194776, 970c96fe0f733683ce4f2b478af21b88 -0, 32, 32, 1, 194644, 8a96248e2821040e4d0d6d32d0a4f1a9 -0, 33, 33, 1, 194940, 70a462d8de0da8b5718bf8fb8034fa38 -0, 34, 34, 1, 194732, 2fb3437abbc0a85b6c46e1b1edd922c9 -0, 35, 35, 1, 194772, 0a0f54e266438e1a840247e1af2fb1f1 -0, 36, 36, 1, 194780, c4d516a459523b1c150d8aad1d5e3a6d -0, 37, 37, 1, 194908, e09db67196513400dd55397a525b73c2 -0, 38, 38, 1, 194148, f3cc9fc8597f8806fbc2a0c13af5b9ba -0, 39, 39, 1, 194168, 2bb82f80c239984fe7c1091ab6afb332 -0, 40, 40, 1, 193604, 6fd128240c540a0655e8f27ff6a50ee9 -0, 41, 41, 1, 194256, 9b49275154b4538abdebbddffe010105 -0, 42, 42, 1, 193912, 6acff798f9cca91347e36ee1ea86183c -0, 43, 43, 1, 194136, f24ca78d9b813ab8bfc720bad2682e7b -0, 44, 44, 1, 193652, d7d927faf59a3b82bd1cce418c13c430 -0, 45, 45, 1, 192960, 8a813fce1d21dd4ad474d06d890a3de5 -0, 46, 46, 1, 192636, 6bbe157ec4f799cfd47a69c5a5cbb0fc -0, 47, 47, 1, 192580, 1c17bf08a3928533a0036bda1fb08ecb -0, 48, 48, 1, 192356, a5b34ac48c82e79ff827f72dddbfc6b0 -0, 49, 49, 1, 191912, afceb467ddffd9697c9566c43f2576f9 +0, 0, 0, 1, 207164, 91bd0a04c522e4a449a2b2729cceb273 +0, 1, 1, 1, 207188, 8a9a23c32503fe30df47a598d319591e +0, 2, 2, 1, 207980, fac02289d860c485b09053119a259772 +0, 3, 3, 1, 206944, bc0251f0a3ad5881cb402d1d071cbfe8 +0, 4, 4, 1, 206200, e3b811ea58b790b171b75c9af46a3637 +0, 5, 5, 1, 207100, 076ca542190996d4ff4380bfff1b8707 +0, 6, 6, 1, 207172, 87d8540012df5c62ffcec97ac4255e44 +0, 7, 7, 1, 206444, 8a4a787dd73b93653ab69622b3fcaa6d +0, 8, 8, 1, 206884, e4ce5916ecee62387a44257f9f7e309f +0, 9, 9, 1, 207632, 67f343e24f47b1eddb47e59831752aab +0, 10, 10, 1, 206916, 6a1d003a2b3c10bd87d5b71a0ecb6fae +0, 11, 11, 1, 206572, 8939adde46e92bf02be301590de578ae +0, 12, 12, 1, 205832, ac36ce0cc201b89aa85aea9f8f85b654 +0, 13, 13, 1, 206712, 1d85faa22ef18e060354d2e2931f78f3 +0, 14, 14, 1, 207496, 2459b868050730ba3c3152443f119e59 +0, 15, 15, 1, 207788, 27616d7494e570814378a35fd72b3d4a +0, 16, 16, 1, 206988, 4f0daddba744ae0ebeea8b55ebc6778b +0, 17, 17, 1, 207056, e2340667064a25a75f67e261fe96baf7 +0, 18, 18, 1, 206440, d487795c5f4a3f338cebfd36b264a760 +0, 19, 19, 1, 206344, 0cd1a4c459402e82d7c89a131d6f75fe +0, 20, 20, 1, 205404, 52ea62992efacc4bf4234507752cd4ed +0, 21, 21, 1, 205776, 7712e82b94fd155c1e0dfec1db19a298 +0, 22, 22, 1, 205600, ec081ebb4e12f35aa47e673c5cd8c858 +0, 23, 23, 1, 207040, 637d7b20ab169db4671d76abc986c20d +0, 24, 24, 1, 207484, a776de1269ad564e1dc21ead94dcc71e +0, 25, 25, 1, 206792, 6aaa68388fb12b2e70eb542819902a97 +0, 26, 26, 1, 206384, b4c4d079d7c75b03e2d3915a8676a64d +0, 27, 27, 1, 206296, 521647a00535f63c241b54699b5d803a +0, 28, 28, 1, 204996, 892f0c216d04dfa120576c0cbbbdb0a2 +0, 29, 29, 1, 205396, fa1b2301c765bb1ca1c85828918462b9 +0, 30, 30, 1, 205812, e40d8da60a07f19b43ab27a13928b87d +0, 31, 31, 1, 206604, 2a06b115a3a400a73ad06b69c90a0768 +0, 32, 32, 1, 206568, e6d367cc3d7bd17a6c470fe86591e56d +0, 33, 33, 1, 206908, 8d53fe57b1043562c50a2fd63fa2ebfa +0, 34, 34, 1, 206388, 3a5544a0a814dbba171d0384c91ea566 +0, 35, 35, 1, 206700, bfe43124bcbbaef9884893c32396f316 +0, 36, 36, 1, 206516, a93e303f30a9269c6d6b59882b668630 +0, 37, 37, 1, 206776, 3044d9c98555d3415fc75b085f8aab0a +0, 38, 38, 1, 205940, 870403f6326de73750a57692a288bc2d +0, 39, 39, 1, 205612, f97b94da7b565f67cb476c73c2196bb1 +0, 40, 40, 1, 205120, 78341e169158f97791ec9a88ee936048 +0, 41, 41, 1, 206132, 83d31e0b40f2850b0767fbd162b4aabd +0, 42, 42, 1, 205984, ba029595b56087c55f324a54cb5e20a6 +0, 43, 43, 1, 205964, d067932b507acda9020837ed271eb09e +0, 44, 44, 1, 205376, 62b45f4949405875f947cd6d5133b76d +0, 45, 45, 1, 204756, ec45bcef0601faff97d89f89bfede4f3 +0, 46, 46, 1, 204704, 59c9d309aa381e39f3b236d332ae516a +0, 47, 47, 1, 204652, c44f8fba96dfb305cdc797ddfa033899 +0, 48, 48, 1, 204460, d0116d06128babcf8ec55205ce89d46a +0, 49, 49, 1, 203624, bbd3523ac263c622541aa67825601fd2 diff --git a/tests/ref/fate/utvideoenc_rgba_none b/tests/ref/fate/utvideoenc_rgba_none index 65f07289d..f388c9101 100644 --- a/tests/ref/fate/utvideoenc_rgba_none +++ b/tests/ref/fate/utvideoenc_rgba_none @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 301284, 55e84c6e1f41e48f47dcefb63e3c1efd -0, 1, 1, 1, 301296, 12dab23dfd2c2d5b48bed2292b876688 -0, 2, 2, 1, 301072, cc2e2889403dcc5d8e36868f07918b9d -0, 3, 3, 1, 301136, 9813d60e613a3a14e639f9af0a5b1fe7 -0, 4, 4, 1, 301140, 58554bb6749e8bbd9476335ac1cb0076 -0, 5, 5, 1, 301164, 37a249286019761a4a3e498e977f9da1 -0, 6, 6, 1, 301168, f3aa11b419ec6f683ad906e7f7a36342 -0, 7, 7, 1, 301272, f489654640f0e42225815ea9c9681201 -0, 8, 8, 1, 301308, f10eb3c1d0324b59bd25c8bc6556aca0 -0, 9, 9, 1, 301268, 2163aa992afef5210d677953d81adb17 -0, 10, 10, 1, 301168, 684d19d14212615ebffa1748a9c552ed -0, 11, 11, 1, 301136, a5c47c30d12dbc679ce932a5988b32e5 -0, 12, 12, 1, 301272, 3a51dc37d7e5ecb4a8db948eade2e0fa -0, 13, 13, 1, 301188, f9f9ed41c233e791e6cd75a34e52edf8 -0, 14, 14, 1, 301096, 63bbfbee6f0fa6745e143dfae40ce7ff -0, 15, 15, 1, 301108, 1fb3340dd1804d27fb40aea6b073e9ce -0, 16, 16, 1, 301248, 476d27f29da8e74db696ff38e81743fc -0, 17, 17, 1, 301300, 84a7f5804a856b7ef640838320634568 -0, 18, 18, 1, 301424, f34006fb55745aac29e265e0362434bf -0, 19, 19, 1, 301456, d9207e54e261d184ddd02f3706e63103 -0, 20, 20, 1, 301408, 89b5a6804bad85025a6a3d23dc539426 -0, 21, 21, 1, 301404, 5987d22d6e3bf18cd2ebea98a1915f57 -0, 22, 22, 1, 301340, 43ff13bb237a7899ecb04fa7d27e94ab -0, 23, 23, 1, 301288, 01b3e148ed6b8a0d05ee628fb21fa4a5 -0, 24, 24, 1, 301360, aa7704007e3c437cfcad4fb83a69594a -0, 25, 25, 1, 301376, 4dea983f0b4a012ba6875aa857d02e91 -0, 26, 26, 1, 301312, e263f1cb0fb19b50751e9a214a4c9d81 -0, 27, 27, 1, 301460, 85ad441664c99c591d6dc427910faa19 -0, 28, 28, 1, 301380, 86ffe8273011763d800dbf6c89942a70 -0, 29, 29, 1, 301448, 500862ea62e1982325d653d4853dcbcd -0, 30, 30, 1, 301452, 91c4390a805e02d1924bd75946bc0b63 -0, 31, 31, 1, 301388, 4eb3040d65948355c4506ee8e8e041ca -0, 32, 32, 1, 301348, ece814a764470f1d80973743a7adaa4b -0, 33, 33, 1, 301324, 2ae0b9af5380c8f98087b90c646af813 -0, 34, 34, 1, 301224, d6a3ba0b543534bd7de9dd82107c468c -0, 35, 35, 1, 301384, 4f4919c1b2502c6e03ddaa83f4c03f15 -0, 36, 36, 1, 301460, b45189bc89e6583f4426c390622fa1fc -0, 37, 37, 1, 301456, db0c5e2bc705c825e554c2da54314746 -0, 38, 38, 1, 301520, 8d01037b2dcbba39d4746758fd53323c -0, 39, 39, 1, 301524, 0a78af44bf49520ae8830060e6011898 -0, 40, 40, 1, 301532, da9032ac97b76ec10f94d74ee878cf41 -0, 41, 41, 1, 301496, 9a22b2a9a3ad897406fc7c3137d41a3b -0, 42, 42, 1, 301572, a14a80ab416cf4a9a1ec24bfc72602a1 -0, 43, 43, 1, 301532, 71ea5a240540a2e08ced8ad78c1a0676 -0, 44, 44, 1, 301516, fffe101d036ed5afee9b6f86267c2a0c -0, 45, 45, 1, 301568, 58ea3a6edaee760d98eadb072fb30796 -0, 46, 46, 1, 301660, 9886e77f5df35d8bd164d598d0f87514 -0, 47, 47, 1, 301668, 1f326eb789974fc853e1db57115ef58b -0, 48, 48, 1, 301684, 08b2eb620b9a7be1bded4744cd4c88db -0, 49, 49, 1, 301668, bfcce1ce5f7c30230aae9a2d67fc8a70 +0, 0, 0, 1, 304028, e1687f63bd131ace3866b61881e8e9a1 +0, 1, 1, 1, 304024, 93067fdad1470b1c2f2fd4ae603a3afe +0, 2, 2, 1, 303932, 2fef08ce570f581373bd48b3a4773acb +0, 3, 3, 1, 303932, 8623d4635239deac16d56085edb8aec1 +0, 4, 4, 1, 303984, ef0a1be76f7c854e5f2724d7a6707f54 +0, 5, 5, 1, 303932, 0e57009f6e93c2e5ce80d6109d9a66f3 +0, 6, 6, 1, 303936, db988d8d6e9ee0383cfc69a201de62e2 +0, 7, 7, 1, 304024, 963e86c081fafed2f757c4aafc9186df +0, 8, 8, 1, 304032, e867c068706bff34a561a4b2c4622fd3 +0, 9, 9, 1, 303960, 0dd6d1cbe6a9fb07e3f3cb4a12c2821a +0, 10, 10, 1, 303944, 424612ce8850b378171ee8bfca5d91ce +0, 11, 11, 1, 303956, f26d5065818f98bbf97aae56fe07b057 +0, 12, 12, 1, 303980, dfd1a61b5a717805a06f19ee899c3917 +0, 13, 13, 1, 303936, 2223f98ac58078c49489811171c713e1 +0, 14, 14, 1, 303808, 6a63bd7cd4cafe5e64dc8dc46f9f3760 +0, 15, 15, 1, 303864, a355699c989795379d1ef2089c98e619 +0, 16, 16, 1, 304008, 07a0c41088846ed77fedc565cfeaeba7 +0, 17, 17, 1, 304000, dbb37a1af0bb534112aac9269b7d7c2c +0, 18, 18, 1, 304048, 3129997c9ba84a0c91ff9d1c48d12d7e +0, 19, 19, 1, 304068, 620b4c964daca105cd1b6bf8d55e86ae +0, 20, 20, 1, 304068, bafaf53530f76d525eafb75a3866b5e7 +0, 21, 21, 1, 304092, 678138b93f07ef8f30ad373499a9caa3 +0, 22, 22, 1, 304060, 4bf8174ff9ee62c13bde29ad5bba3fc9 +0, 23, 23, 1, 303976, e6e926057f49e69e2ea8e679871e449a +0, 24, 24, 1, 304040, f81ba4d36df7e8967a16e7de5c7a023b +0, 25, 25, 1, 304084, a5a63a22e6bc3a54bfbd60852ca9da60 +0, 26, 26, 1, 304056, df9bd50b9dd7437afb3671c99e2e1746 +0, 27, 27, 1, 304076, 785a2a7de44e83f1111e66165b3d0765 +0, 28, 28, 1, 304132, ab01bacd7aee91ab80b30a48f54ec4d7 +0, 29, 29, 1, 304160, 4893296140e7ee6f2d194bc279f928f3 +0, 30, 30, 1, 304136, 6046c7516a5e8db2f4dd3b1286ad46c0 +0, 31, 31, 1, 304088, e6dbc1ec86cb678bab6a1ca0e93888d0 +0, 32, 32, 1, 303980, 66db98674c107af297a3de01c047ebce +0, 33, 33, 1, 303964, e2ce0a2ee5ba8de50960873a8405c001 +0, 34, 34, 1, 303900, 7ae96a39e66e0abe63e298f45477c0ec +0, 35, 35, 1, 304040, d5fc8f7809470bc40935285d4ed69a80 +0, 36, 36, 1, 304088, efae0966a7e421c3107016df862b0429 +0, 37, 37, 1, 304120, c6a3bf8991bf2b559f27d5ea9ae76d08 +0, 38, 38, 1, 304144, 588ac89c403c5d3ca9289fbd339fdb74 +0, 39, 39, 1, 304136, a3824537484dd2fc25dde9ec2974068c +0, 40, 40, 1, 304172, e1a024aa9faba0ee0cb98e41cef254c9 +0, 41, 41, 1, 304116, c26c4c053d53b70c97cbf989cb51a15d +0, 42, 42, 1, 304140, 4d13ee2a3b32ba3f080fffa7ca2db6e6 +0, 43, 43, 1, 304116, fb02b57f9a9fafa7bc6d2a35a68548fc +0, 44, 44, 1, 304088, 6daa494c1ed11c9ea8da6c83eb473ce7 +0, 45, 45, 1, 304196, 8886953ff026efef28f4af12ce5239b6 +0, 46, 46, 1, 304200, 51ff2c8552b8b044a1a183330a188d62 +0, 47, 47, 1, 304208, 72fcd3dbf45284bb434ad3660f8a1ddf +0, 48, 48, 1, 304204, 1d5e2170963d70acea2ad01e1486d490 +0, 49, 49, 1, 304184, 6eec23c3d4402f7a0ab4de16fde86462 diff --git a/tests/ref/fate/utvideoenc_yuv444_left b/tests/ref/fate/utvideoenc_yuv444_left new file mode 100644 index 000000000..1b8d92576 --- /dev/null +++ b/tests/ref/fate/utvideoenc_yuv444_left @@ -0,0 +1,60 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#extradata 0, 16, e46c7123194c0ebf19a23e5cefebaa63 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: utvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 144080, 678b4a3ece35971c3e0f199fcab2b4a1 +0, 1, 1, 1, 144120, d0c326ed062b569a04ea84359e43cfde +0, 2, 2, 1, 144956, 32e2d8a1dc22b1d837e8f70509767d7d +0, 3, 3, 1, 143324, 6fff1691c498ccf1cf848147dcc1b62c +0, 4, 4, 1, 142464, df4caa8316ec987fe3cba4a76c0976f0 +0, 5, 5, 1, 144068, 2cc92f54850a45d76b8a959d62c28408 +0, 6, 6, 1, 143840, c80e0e9945a92869ca639b59118f24f3 +0, 7, 7, 1, 143536, 682a3148911f94daa333e12a505d689f +0, 8, 8, 1, 143736, af692d8d5fe2e23f9e16c7164ceaaeb5 +0, 9, 9, 1, 144076, 13412473483a727e8cced00d0d0fbb78 +0, 10, 10, 1, 144012, 4f1402c7d25ee222329cc007aa4df345 +0, 11, 11, 1, 143520, cc4b83f407d031cc4a166c3210583599 +0, 12, 12, 1, 141640, e4a4d1b88c7aabfcc40c51ff80305f70 +0, 13, 13, 1, 143096, b3de93652c190bc88dd6e17a27db4ebf +0, 14, 14, 1, 144704, 48ce5d6a84b965f38f5e4a46e8bfd0c3 +0, 15, 15, 1, 144520, 936970ae76c23e6a7880f2c875c1fb66 +0, 16, 16, 1, 143704, 32d9a3e4118e1134f3c0ead846805aaf +0, 17, 17, 1, 143648, 4214224b843fab53ae45921426de1892 +0, 18, 18, 1, 142920, 22b1c3a09f23fa262d7ffa2fb4347f3a +0, 19, 19, 1, 142604, d24c0ba247bb38bf7bdfc348d7c6fdf1 +0, 20, 20, 1, 141928, 8115cdd0fb51fa90821f93900c8cc980 +0, 21, 21, 1, 142072, f6d87afe383aa9a85b89832e422859e0 +0, 22, 22, 1, 142204, ced75258ae7001a8a4029423d61abf06 +0, 23, 23, 1, 143420, 686a5ded45cd70af9e699e9919da9cc7 +0, 24, 24, 1, 144552, 5a1e0f522e74a1284b86c5d0e185f16d +0, 25, 25, 1, 143328, f54e6787ac2f3ac0e925388b66c95b2a +0, 26, 26, 1, 142584, 652dda504ace9c4e1569319ef6cd333d +0, 27, 27, 1, 142084, 3eafb87f47844ce6d0572af051d2e25b +0, 28, 28, 1, 140196, 92b60cf33e5c430f3e92a39bb4389096 +0, 29, 29, 1, 140152, 658a331d3f5ee1bb50392f3835aed56d +0, 30, 30, 1, 141484, b54db7d5978d99f7192dd2008438ab41 +0, 31, 31, 1, 142360, ed84a9d2241ade4c36f95eaa1ae00b0e +0, 32, 32, 1, 142744, 7dbb99de3a4a81de5564bb577471128d +0, 33, 33, 1, 144360, bd26a71b0824a04badfffa0653f0ac00 +0, 34, 34, 1, 143464, 11fe56173423180d581bc52fe044657a +0, 35, 35, 1, 142856, 9f690fa8727669ba8640032933eb8235 +0, 36, 36, 1, 142108, b5c182f3f0e6d307f598dc55f51f9d51 +0, 37, 37, 1, 142492, ab7b6b446b4f5f5ec2b2eb52f934523c +0, 38, 38, 1, 140532, 3fda7e5443dcf59e52f523bcf863d5d2 +0, 39, 39, 1, 140288, 1426cb304a219876586ba5c161809fac +0, 40, 40, 1, 140540, 3a69f372875e2cd6ec5b49498e1f1a05 +0, 41, 41, 1, 141868, aca8f0bd1b29c4142b80e5e3e59aeb75 +0, 42, 42, 1, 141892, 91bf3847703041b4fbe87602e78fb577 +0, 43, 43, 1, 142080, f1b28c53e1068a6305ebb6d4862aebf1 +0, 44, 44, 1, 141220, 188ffeef2973b490364e8cf01fc2d8e6 +0, 45, 45, 1, 139908, 1eaa1194f719aa6da4c7ab4dddcee4ce +0, 46, 46, 1, 138868, 2243b5d473d6df2ea283752fe799c95b +0, 47, 47, 1, 139276, d74f2cbfac00177d848fb1b1e223e654 +0, 48, 48, 1, 139312, 27054be184a1028a86c5e3406418a92c +0, 49, 49, 1, 138132, feb653f902c92cfd1954b61b9d1149f2 diff --git a/tests/ref/fate/utvideoenc_yuv444_median b/tests/ref/fate/utvideoenc_yuv444_median new file mode 100644 index 000000000..f690a3808 --- /dev/null +++ b/tests/ref/fate/utvideoenc_yuv444_median @@ -0,0 +1,60 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#extradata 0, 16, e46c7123194c0ebf19a23e5cefebaa63 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: utvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 136492, 5e3cc78fe9e404b0eca7c2df98841eab +0, 1, 1, 1, 136336, cec7bad80feac6e16a3d84734ae473d8 +0, 2, 2, 1, 137296, cb43d766c513da815c5964f1f48c2e49 +0, 3, 3, 1, 136088, 4c8900602c580526057b52bb14161274 +0, 4, 4, 1, 135276, a9b134a0e49812ff929cdd57d8a00907 +0, 5, 5, 1, 136668, 0b9dc3cd51ce5c674315c06bd677fcea +0, 6, 6, 1, 136480, 16020ff181e477f1b01b86aa5070bf7c +0, 7, 7, 1, 135876, 557f1f43cdfc06603f3bd97bb9d44394 +0, 8, 8, 1, 136204, c03b7cd310961ef9fe8734f45a9276e2 +0, 9, 9, 1, 136796, b668c63bed0b2de4d182cf0281e71ecf +0, 10, 10, 1, 136252, 7758777682f6e3ea84010cbaf2645a6e +0, 11, 11, 1, 136284, 699e6ab66911cdd0fa357c069537e3ec +0, 12, 12, 1, 135096, 65d4d3b6e1bbf6d67baca1f346d06735 +0, 13, 13, 1, 136088, 7d69fb86f67b3fd3df4008cb03d9f1ef +0, 14, 14, 1, 136876, abca4a026bf93da58283d5ddd51cead4 +0, 15, 15, 1, 137096, f5bb254ede8a9ed4c07fb80fb1a301d7 +0, 16, 16, 1, 136232, cdbe70b4b7051b9c1092ea626e825658 +0, 17, 17, 1, 136308, acb31052249c48b729842938977172e8 +0, 18, 18, 1, 135444, bf38e56e2a152154b0401507550b5605 +0, 19, 19, 1, 135300, 1737341c361f656feffc86903da34647 +0, 20, 20, 1, 134548, c28e9c441544b7c51cf76afd4b5a2799 +0, 21, 21, 1, 134816, 5b8ba0d205863105d723afcc28274fb2 +0, 22, 22, 1, 134776, 90c5ac5ed83ed6a43b4fe14c0ee07dc5 +0, 23, 23, 1, 136332, 3ca065b60b4fbc5b04f68e6bb900d862 +0, 24, 24, 1, 136724, 283b23278ca40dc93a326e96e5c22629 +0, 25, 25, 1, 135948, 6568fb8593edce20f294a936ab11153b +0, 26, 26, 1, 135400, 22abaf0c3184a79cb90b4d7fe6cee897 +0, 27, 27, 1, 135056, abd6117e31af2d136c0df8ab1db64599 +0, 28, 28, 1, 133676, 67a65017fb2a232a726717628fbe1d95 +0, 29, 29, 1, 133700, 7dff3d958ecbedc691d3b188084d26d9 +0, 30, 30, 1, 134444, 192c98c1a7c2f4a15c7aa59607b7d1ff +0, 31, 31, 1, 135388, 32d1aba6d499162345fcb0ca858558d5 +0, 32, 32, 1, 135680, 77cd1f8ddf7ce977ba9ff074d595e033 +0, 33, 33, 1, 136404, 9eb0213f0d66d957f668f88d426f014f +0, 34, 34, 1, 135816, 337b4082181e8627f2fe9c852681688f +0, 35, 35, 1, 135616, c73c95e75669ce9dafd0ac253239430a +0, 36, 36, 1, 135136, e4e5515dbb05b855b4ce42fe1638d119 +0, 37, 37, 1, 135572, 987ffdc8d0c142e92dc02190f73afd70 +0, 38, 38, 1, 134748, 8a01538b863e51066f896f18ad8cc68b +0, 39, 39, 1, 134428, 3096e9435e5813d54013bf5c86e15c4f +0, 40, 40, 1, 133796, 78d3952c814172173b24881e110c861f +0, 41, 41, 1, 135052, b0c2bf0b1047dd71268d3c3114b655d8 +0, 42, 42, 1, 134768, 653862b7e519c299278186920217a303 +0, 43, 43, 1, 134692, 26fb91814efadd0120f247d6b5f22d81 +0, 44, 44, 1, 134164, e85390622cb7eb6618512ead58d578c6 +0, 45, 45, 1, 133380, 7c04e5015f89c24713227329aa1820fb +0, 46, 46, 1, 132872, 877db229c19c9719bd9b19d0dab1c169 +0, 47, 47, 1, 132864, c4a86326303f96d53cb267111ed199e5 +0, 48, 48, 1, 132644, 7dd3fe41c535d168eb0450d96171ec0f +0, 49, 49, 1, 131772, c430f15c1683207fbec250dc9d7a2b13 diff --git a/tests/ref/fate/utvideoenc_yuv444_none b/tests/ref/fate/utvideoenc_yuv444_none new file mode 100644 index 000000000..880b81376 --- /dev/null +++ b/tests/ref/fate/utvideoenc_yuv444_none @@ -0,0 +1,60 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#extradata 0, 16, e46c7123194c0ebf19a23e5cefebaa63 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: utvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 286288, f77b660b13f4ca2d906dbe620019224f +0, 1, 1, 1, 286388, 61c3e9c05be428c2adf312257580d528 +0, 2, 2, 1, 286148, cf2d8de31997ba6c9c87ca0203295ffd +0, 3, 3, 1, 286124, 981f9eeeed512af38eac7c5df0693b85 +0, 4, 4, 1, 286644, be9e95106ca59737b1154b865e917110 +0, 5, 5, 1, 286280, e70b66f13e4a08c10e1d014ac1be0cf9 +0, 6, 6, 1, 286176, b20a78e4bcd02d7fedc0f00af8276847 +0, 7, 7, 1, 286132, 80cc66c88ea015b62bbf46ae188eed95 +0, 8, 8, 1, 285968, 446ae00d0e1fc233b66ecb35c720464d +0, 9, 9, 1, 285888, 9d4b29bfd62e5cac2d77185e19706325 +0, 10, 10, 1, 285792, bc74548c1ed37dc1d6ca523e00b83ed7 +0, 11, 11, 1, 285412, f7234684c90e0dfcfd7ff9a7612b9cb9 +0, 12, 12, 1, 286080, 3873173b7da6113b058c0e50d1fb2ac9 +0, 13, 13, 1, 285524, 90654181491240e1883cfa8e9dcbc53a +0, 14, 14, 1, 285628, 5ae2de1a60c2586af4a27dca27e0d614 +0, 15, 15, 1, 285620, 9d78ee5f1390c05af2677bedf2b088e4 +0, 16, 16, 1, 285768, 7c47cbbba7af11ace3233c904e628242 +0, 17, 17, 1, 285880, 8292ea2eb80b860edf0747707eb99966 +0, 18, 18, 1, 285956, 17aef410ca3fec63ef83185401e005a3 +0, 19, 19, 1, 285992, 779819d6d090a67261ef3611f7b50ad6 +0, 20, 20, 1, 285920, 52fbe43f864350643cb4e8a57fcf8f63 +0, 21, 21, 1, 286040, c2e7919e6e20c7fcf78c0229e4d456d4 +0, 22, 22, 1, 285844, edc46036a229878d26a8df1f6dfbd661 +0, 23, 23, 1, 285868, 7e5a9af2d70dc57a7ca0a03f88a3a1a9 +0, 24, 24, 1, 286056, 174d2c8aca73cb5481e12a5a22516d02 +0, 25, 25, 1, 285836, cf1d28a88aa4fc2a5e16e03e2081919f +0, 26, 26, 1, 286004, 2ffd12c7501e4709939712a62945ec29 +0, 27, 27, 1, 286264, 61962127ef2a4612a9a352119b7444dd +0, 28, 28, 1, 286632, 9355ea7ef38424633b9e0b77ebb23d77 +0, 29, 29, 1, 286508, a741f67693b0154355966a1b07265939 +0, 30, 30, 1, 286124, 0fb2a3a0b6e525907b6d0c50ca8f7be1 +0, 31, 31, 1, 286308, 89fd53c38119426cdd63be714e857dac +0, 32, 32, 1, 286032, 674d9043981cce19c39e2c6d405d856a +0, 33, 33, 1, 285672, 7b9678e7772b71abf5a95fa967d319af +0, 34, 34, 1, 285520, 6e626d4c722ccafea6600a62c093a47a +0, 35, 35, 1, 285828, 49e9023d9c820798af6b445ec1d87b13 +0, 36, 36, 1, 286344, 6cf611f3ef47442659e3ce3807d3a480 +0, 37, 37, 1, 286360, a0eca88afed37e0747b1fa61c7e36713 +0, 38, 38, 1, 286264, 5b3e605f71b8bab3aa2cc3ed439c6f8a +0, 39, 39, 1, 286096, f9a1c5beca596e2b5eef2392b0adb01e +0, 40, 40, 1, 286284, eb2440f6539413efc86e5a0cd545ecd4 +0, 41, 41, 1, 285816, 520d3344f335b580bfb2fad58b1643b4 +0, 42, 42, 1, 285864, 48ed0d9ed707808298800c87f2d61d75 +0, 43, 43, 1, 286108, 9cb952285049f8354ab7e00c0ab2f7d5 +0, 44, 44, 1, 286308, 7ba07e4cc04cd42272ab75e1a65703ca +0, 45, 45, 1, 286552, 55722a7bc60c9eb68a94fd0e8ba3ba4f +0, 46, 46, 1, 286456, e3e54e031bcf3067360955817690a755 +0, 47, 47, 1, 286240, 96aa493b2b8d264ffb0d49c952594c11 +0, 48, 48, 1, 286128, 6e7e04eec86f257aa46c59f0e8b6b22c +0, 49, 49, 1, 286128, ab72c8a01a095040efb1d4cb1fddbd4a diff --git a/tests/ref/fate/vp8-alpha b/tests/ref/fate/vp8-alpha index 4922d5273..cc096c6d3 100644 --- a/tests/ref/fate/vp8-alpha +++ b/tests/ref/fate/vp8-alpha @@ -3,7 +3,7 @@ #codec_id 0: vp8 #dimensions 0: 320x213 #sar 0: 1/1 -0, 0, 0, 33, 2108, 0x59b92a34, S=2, 1900, 0x8fb3adc5, 8, 0x00000000 +0, 0, 0, 33, 2108, 0x59b92a34, S=2, 1900, 0x8fb3adc5, 12, 0x00000000 0, 32, 32, 33, 142, 0x2f2a3fed, F=0x0, S=1, 160, 0xa13346af 0, 65, 65, 33, 157, 0x17804767, F=0x0, S=1, 209, 0x64115f15 0, 99, 99, 33, 206, 0x537262ca, F=0x0, S=1, 317, 0x44a09dd0 diff --git a/tests/ref/lavf/ffm b/tests/ref/lavf/ffm deleted file mode 100644 index d9fa8d52c..000000000 --- a/tests/ref/lavf/ffm +++ /dev/null @@ -1,3 +0,0 @@ -ca2a450cd0d1e299514a345923b4c82a *./tests/data/lavf/lavf.ffm -376832 ./tests/data/lavf/lavf.ffm -./tests/data/lavf/lavf.ffm CRC=0x000e23ae diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf index b9c37334a..7318447ec 100644 --- a/tests/ref/lavf/mxf +++ b/tests/ref/lavf/mxf @@ -1,9 +1,9 @@ -1c06a9d69b6e309579784db5ecb0b69f *./tests/data/lavf/lavf.mxf +d4140129463dec64bdb4a7d7ad1b0c82 *./tests/data/lavf/lavf.mxf 525369 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0x8dddfaab -50b4f9ca0493e6d83f4c52dc3aa2b7a5 *./tests/data/lavf/lavf.mxf +a27bb8cd5e185ea13b0a8daa4eb221cd *./tests/data/lavf/lavf.mxf 560697 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0xf21b1b48 -4b71b154ae37364c8028cb50850a54c5 *./tests/data/lavf/lavf.mxf +395bf0047c97ceca96935357166b94c7 *./tests/data/lavf/lavf.mxf 525369 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0x8dddfaab diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10 index 134db876d..2384d427b 100644 --- a/tests/ref/lavf/mxf_d10 +++ b/tests/ref/lavf/mxf_d10 @@ -1,3 +1,3 @@ -73c0cb416548c33d0651c59519a8f7e2 *./tests/data/lavf/lavf.mxf_d10 +f4694941b0cd5b5e3c91064d84dbd345 *./tests/data/lavf/lavf.mxf_d10 5330989 ./tests/data/lavf/lavf.mxf_d10 ./tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488 diff --git a/tests/ref/lavf/mxf_dv25 b/tests/ref/lavf/mxf_dv25 index 85094828d..e836b1424 100644 --- a/tests/ref/lavf/mxf_dv25 +++ b/tests/ref/lavf/mxf_dv25 @@ -1,3 +1,3 @@ -1871bd11947924116776201f24fd0adf *./tests/data/lavf/lavf.mxf_dv25 +1ca8143bf6cf322fd39f6e856959d502 *./tests/data/lavf/lavf.mxf_dv25 3833389 ./tests/data/lavf/lavf.mxf_dv25 ./tests/data/lavf/lavf.mxf_dv25 CRC=0xbdaf7f52 diff --git a/tests/ref/lavf/mxf_dvcpro50 b/tests/ref/lavf/mxf_dvcpro50 index 1d0cf7999..bb3d6b928 100644 --- a/tests/ref/lavf/mxf_dvcpro50 +++ b/tests/ref/lavf/mxf_dvcpro50 @@ -1,3 +1,3 @@ -6c9cb62911ac16c3b55f0ad0b052c05b *./tests/data/lavf/lavf.mxf_dvcpro50 +987fd4b2abb36433fba0e35f4092efc6 *./tests/data/lavf/lavf.mxf_dvcpro50 7430189 ./tests/data/lavf/lavf.mxf_dvcpro50 ./tests/data/lavf/lavf.mxf_dvcpro50 CRC=0xe3bbe4b4 diff --git a/tests/ref/lavf/mxf_opatom b/tests/ref/lavf/mxf_opatom index ea1190c06..1cc612e62 100644 --- a/tests/ref/lavf/mxf_opatom +++ b/tests/ref/lavf/mxf_opatom @@ -1,3 +1,3 @@ -962c2cd582340f8961a8283636093abf *./tests/data/lavf/lavf.mxf_opatom +b8fe60f7457b83709f33357d04c8db0c *./tests/data/lavf/lavf.mxf_opatom 4717113 ./tests/data/lavf/lavf.mxf_opatom ./tests/data/lavf/lavf.mxf_opatom CRC=0xf55aa22a diff --git a/tests/ref/lavf/mxf_opatom_audio b/tests/ref/lavf/mxf_opatom_audio index 953df9094..deed55e52 100644 --- a/tests/ref/lavf/mxf_opatom_audio +++ b/tests/ref/lavf/mxf_opatom_audio @@ -1,3 +1,3 @@ -d4ad5a0faf410a9d9e99b3328143e89d *./tests/data/lavf/lavf.mxf_opatom_audio +e7da52bd591e6eddb4e1af381a4e5bd4 *./tests/data/lavf/lavf.mxf_opatom_audio 101945 ./tests/data/lavf/lavf.mxf_opatom_audio ./tests/data/lavf/lavf.mxf_opatom_audio CRC=0xd155c6ff diff --git a/tests/ref/lavf/wav_peak b/tests/ref/lavf/wav_peak index aa7e5fc49..861b246d7 100644 --- a/tests/ref/lavf/wav_peak +++ b/tests/ref/lavf/wav_peak @@ -1,3 +1,3 @@ -35148d1f6e66b0080893851d917ecbf4 *./tests/data/lavf/lavf.peak.wav +105805963fb767d00da056f42f32d9f3 *./tests/data/lavf/lavf.peak.wav 89094 ./tests/data/lavf/lavf.peak.wav ./tests/data/lavf/lavf.peak.wav CRC=0x3a1da17e diff --git a/tests/ref/lavf/wav_peak_only b/tests/ref/lavf/wav_peak_only index dccd0e72f..b203d0345 100644 --- a/tests/ref/lavf/wav_peak_only +++ b/tests/ref/lavf/wav_peak_only @@ -1,2 +1,2 @@ -b609a363e6d490710ed52231a8d09d3c *./tests/data/lavf/lavf.peak_only.wav +f1a8aeeae8069f3992c4d780436c3d23 *./tests/data/lavf/lavf.peak_only.wav 832 ./tests/data/lavf/lavf.peak_only.wav diff --git a/tests/ref/seek/extra-mp4 b/tests/ref/seek/extra-mp4 index c25544c09..c17ce4003 100644 --- a/tests/ref/seek/extra-mp4 +++ b/tests/ref/seek/extra-mp4 @@ -28,10 +28,10 @@ ret: 0 st: 0 flags:0 dts: 50.633333 pts: 50.733333 pos:5926157 size: 13 ret: 0 st: 0 flags:0 dts: 50.666667 pts: 50.666667 pos:5927464 size: 150 ret: 0 st: 0 flags:0 dts: 50.700000 pts: 50.700000 pos:5927614 size: 176 ret: 0 st:-1 flags:1 ts: 153.470835 -ret: 0 st: 0 flags:1 dts: 153.466667 pts: 153.500000 pos:15867700 size: 96169 -ret: 0 st: 0 flags:0 dts: 153.500000 pts: 153.533333 pos:15963869 size: 785 -ret: 0 st: 0 flags:0 dts: 153.533333 pts: 153.633333 pos:15964654 size: 3135 -ret: 0 st: 0 flags:0 dts: 153.566667 pts: 153.566667 pos:15967789 size: 859 +ret: 0 st: 0 flags:1 dts: 151.966667 pts: 152.000000 pos:15705355 size:146924 +ret: 0 st: 0 flags:0 dts: 152.000000 pts: 152.100000 pos:15852279 size: 1355 +ret: 0 st: 0 flags:0 dts: 152.033333 pts: 152.033333 pos:15853634 size: 211 +ret: 0 st: 0 flags:0 dts: 152.066667 pts: 152.066667 pos:15853845 size: 217 ret: 0 st: 0 flags:0 ts: 76.365000 ret: 0 st: 0 flags:1 dts: 77.833333 pts: 77.866667 pos:8659657 size: 41182 ret: 0 st: 0 flags:0 dts: 77.866667 pts: 77.966667 pos:8700839 size: 4197 @@ -83,10 +83,10 @@ ret: 0 st: 0 flags:0 dts: 101.333333 pts: 101.433333 pos:11049548 size: ret: 0 st: 0 flags:0 dts: 101.366667 pts: 101.366667 pos:11053072 size: 562 ret: 0 st: 0 flags:0 dts: 101.400000 pts: 101.400000 pos:11053634 size: 599 ret: 0 st:-1 flags:0 ts: 25.306672 -ret: 0 st: 0 flags:1 dts: 27.400000 pts: 27.433333 pos:2674605 size:127383 -ret: 0 st: 0 flags:0 dts: 27.433333 pts: 27.466667 pos:2801988 size: 68 -ret: 0 st: 0 flags:0 dts: 27.466667 pts: 27.500000 pos:2802268 size: 1754 -ret: 0 st: 0 flags:0 dts: 27.500000 pts: 27.533333 pos:2804022 size: 4071 +ret: 0 st: 0 flags:1 dts: 25.300000 pts: 25.333333 pos:2607246 size: 40273 +ret: 0 st: 0 flags:0 dts: 25.333333 pts: 25.433333 pos:2647519 size: 2959 +ret: 0 st: 0 flags:0 dts: 25.366667 pts: 25.366667 pos:2650478 size: 197 +ret: 0 st: 0 flags:0 dts: 25.400000 pts: 25.400000 pos:2650675 size: 230 ret: 0 st:-1 flags:1 ts: 128.200839 ret: 0 st: 0 flags:1 dts: 127.833333 pts: 127.866667 pos:13514072 size: 67382 ret: 0 st: 0 flags:0 dts: 127.866667 pts: 127.966667 pos:13581454 size: 2936 diff --git a/tests/ref/seek/lavf-ffm b/tests/ref/seek/lavf-ffm deleted file mode 100644 index eceed1a2c..000000000 --- a/tests/ref/seek/lavf-ffm +++ /dev/null @@ -1,53 +0,0 @@ -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 0 flags:0 ts: 0.788334 -ret: 0 st: 1 flags:1 dts: 0.825011 pts: 0.825011 pos: 327680 size: 209 -ret: 0 st: 0 flags:1 ts:-0.317499 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 1 flags:0 ts: 2.576668 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:1 ts: 1.470835 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 1 flags:1 dts: 0.380930 pts: 0.380930 pos: 163840 size: 209 -ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 0 flags:0 ts: 2.153336 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 0 flags:1 ts: 1.047503 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:0 ts:-0.058330 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 1 flags:1 ts: 2.835837 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 1 flags:1 dts: 0.642154 pts: 0.642154 pos: 274432 size: 209 -ret: 0 st: 0 flags:0 ts:-0.481662 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 0 flags:1 ts: 2.412505 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:0 ts: 1.306672 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:1 ts: 0.200839 -ret: 0 st: 1 flags:1 dts: 0.224195 pts: 0.224195 pos: 114688 size: 209 -ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 0 flags:0 ts: 0.883340 -ret: 0 st: 0 flags:0 dts: 0.880000 pts: 0.920000 pos: 339968 size: 12307 -ret: 0 st: 0 flags:1 ts:-0.222493 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 1 flags:0 ts: 2.671674 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:1 ts: 1.565841 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 1 flags:1 dts: 0.485420 pts: 0.485420 pos: 221184 size: 209 -ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 diff --git a/tests/ref/seek/lavf-mxf_d10 b/tests/ref/seek/lavf-mxf_d10 index 17cca29c0..5a682f092 100644 --- a/tests/ref/seek/lavf-mxf_d10 +++ b/tests/ref/seek/lavf-mxf_d10 @@ -8,9 +8,9 @@ ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4265984 size:150000 ret: 0 st: 0 flags:1 ts:-0.320000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:0 ts: 2.576667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 1.470833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 0.365002 ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1923072 size:150000 ret: 0 st:-1 flags:1 ts:-0.740831 @@ -22,7 +22,7 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:0 ts:-0.058333 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 1.730004 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:1 ts: 0.624171 @@ -32,7 +32,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 0 flags:1 ts: 2.400000 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:0 ts: 1.306667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 0.200833 ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1071104 size:150000 ret: 0 st:-1 flags:0 ts:-0.904994 @@ -44,9 +44,9 @@ ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4691968 size:150000 ret: 0 st: 0 flags:1 ts:-0.240000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:0 ts: 2.671667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 0.460008 ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2562048 size:150000 ret: 0 st:-1 flags:1 ts:-0.645825 diff --git a/tests/ref/vsynth/vsynth1-cinepak b/tests/ref/vsynth/vsynth1-cinepak index f1dfcd81d..e47ae26b6 100644 --- a/tests/ref/vsynth/vsynth1-cinepak +++ b/tests/ref/vsynth/vsynth1-cinepak @@ -1,4 +1,4 @@ -546c7c1069f9e418aa787f469b693b94 *tests/data/fate/vsynth1-cinepak.mov -99465 tests/data/fate/vsynth1-cinepak.mov -bee091c200262be3427a233a2812388c *tests/data/fate/vsynth1-cinepak.out.rawvideo -stddev: 8.46 PSNR: 29.58 MAXDIFF: 105 bytes: 7603200/ 456192 +cd28e47a6ac396240a3fee69f15625d1 *tests/data/fate/vsynth1-cinepak.avi +408616 tests/data/fate/vsynth1-cinepak.avi +e74066a028c708f467272884ecd3f7d3 *tests/data/fate/vsynth1-cinepak.out.rawvideo +stddev: 61.38 PSNR: 12.37 MAXDIFF: 225 bytes: 7603200/ 921600 diff --git a/tests/ref/vsynth/vsynth1-ffvhuff420p12 b/tests/ref/vsynth/vsynth1-ffvhuff420p12 index 0d80bd6d6..d4b22f3b4 100644 --- a/tests/ref/vsynth/vsynth1-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth1-ffvhuff420p12 @@ -1,4 +1,4 @@ 866485c954242232878e40f0389790dd *tests/data/fate/vsynth1-ffvhuff420p12.avi 14205356 tests/data/fate/vsynth1-ffvhuff420p12.avi -b48f32c140712e8c7bf81cfdd66ae312 *tests/data/fate/vsynth1-ffvhuff420p12.out.rawvideo -stddev: 0.68 PSNR: 51.47 MAXDIFF: 1 bytes: 7603200/ 7603200 +c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p10 b/tests/ref/vsynth/vsynth1-vc2-420p10 index 037c77cac..025a1cc77 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p10 +++ b/tests/ref/vsynth/vsynth1-vc2-420p10 @@ -1,4 +1,4 @@ 1365742985b6315f6796c765aa17f39e *tests/data/fate/vsynth1-vc2-420p10.mov 1417047 tests/data/fate/vsynth1-vc2-420p10.mov -d3deedfa461a2696f82910890412fa2d *tests/data/fate/vsynth1-vc2-420p10.out.rawvideo -stddev: 0.60 PSNR: 52.47 MAXDIFF: 1 bytes: 7603200/ 760320 +387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p10.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p12 b/tests/ref/vsynth/vsynth1-vc2-420p12 index b0c56afcd..719f0d5f3 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p12 +++ b/tests/ref/vsynth/vsynth1-vc2-420p12 @@ -1,4 +1,4 @@ 08a844d17940cd612da269fb08430628 *tests/data/fate/vsynth1-vc2-420p12.mov 1746007 tests/data/fate/vsynth1-vc2-420p12.mov -5a78509638a96b0fa17c1b7e9159fd24 *tests/data/fate/vsynth1-vc2-420p12.out.rawvideo -stddev: 0.67 PSNR: 51.48 MAXDIFF: 1 bytes: 7603200/ 760320 +387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-cinepak b/tests/ref/vsynth/vsynth2-cinepak index 18eb1d59a..835de78d1 100644 --- a/tests/ref/vsynth/vsynth2-cinepak +++ b/tests/ref/vsynth/vsynth2-cinepak @@ -1,4 +1,4 @@ -cc0879f1993cdd6231e2c3b9c2c015a0 *tests/data/fate/vsynth2-cinepak.mov -88400 tests/data/fate/vsynth2-cinepak.mov -12c480911ebb89762dc49af003b176c7 *tests/data/fate/vsynth2-cinepak.out.rawvideo -stddev: 5.07 PSNR: 34.02 MAXDIFF: 59 bytes: 7603200/ 456192 +663a2804f421709208c76f6e34e7bea5 *tests/data/fate/vsynth2-cinepak.avi +400402 tests/data/fate/vsynth2-cinepak.avi +2c761c3c8cda083eb8f54b2df72b257b *tests/data/fate/vsynth2-cinepak.out.rawvideo +stddev: 80.96 PSNR: 9.96 MAXDIFF: 227 bytes: 7603200/ 921600 diff --git a/tests/ref/vsynth/vsynth2-ffvhuff420p12 b/tests/ref/vsynth/vsynth2-ffvhuff420p12 index 82c467ac3..f97edfbf4 100644 --- a/tests/ref/vsynth/vsynth2-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth2-ffvhuff420p12 @@ -1,4 +1,4 @@ 3ab9567895bf1ec31a82aadf16a5da0e *tests/data/fate/vsynth2-ffvhuff420p12.avi 10562808 tests/data/fate/vsynth2-ffvhuff420p12.avi -542327cb5ca7708085513ffc3d7c693c *tests/data/fate/vsynth2-ffvhuff420p12.out.rawvideo -stddev: 0.72 PSNR: 50.87 MAXDIFF: 1 bytes: 7603200/ 7603200 +36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p10 b/tests/ref/vsynth/vsynth2-vc2-420p10 index 9de40d227..48d97d60e 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p10 +++ b/tests/ref/vsynth/vsynth2-vc2-420p10 @@ -1,4 +1,4 @@ 1197f8108683b9eb6b0777adb2db1aa8 *tests/data/fate/vsynth2-vc2-420p10.mov 1181271 tests/data/fate/vsynth2-vc2-420p10.mov -75174cb90e76c433f6d769531d573ac2 *tests/data/fate/vsynth2-vc2-420p10.out.rawvideo -stddev: 0.63 PSNR: 52.11 MAXDIFF: 1 bytes: 7603200/ 760320 +01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p10.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p12 b/tests/ref/vsynth/vsynth2-vc2-420p12 index 660a1eeb5..9b9ccb8ec 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p12 +++ b/tests/ref/vsynth/vsynth2-vc2-420p12 @@ -1,4 +1,4 @@ 0e6b3aefd70fca45e67dc8cbc99640e8 *tests/data/fate/vsynth2-vc2-420p12.mov 1525079 tests/data/fate/vsynth2-vc2-420p12.mov -b4d45651e20faa7a0bb84a0738638c48 *tests/data/fate/vsynth2-vc2-420p12.out.rawvideo -stddev: 0.73 PSNR: 50.84 MAXDIFF: 1 bytes: 7603200/ 760320 +01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth3-ffvhuff420p12 b/tests/ref/vsynth/vsynth3-ffvhuff420p12 index 72d412d64..201ec7658 100644 --- a/tests/ref/vsynth/vsynth3-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth3-ffvhuff420p12 @@ -1,4 +1,4 @@ e5a178d75afeda6df1d4eb6f7cdfa3a0 *tests/data/fate/vsynth3-ffvhuff420p12.avi 175260 tests/data/fate/vsynth3-ffvhuff420p12.avi -ee95a44ccd612b5057860b43fe9775d6 *tests/data/fate/vsynth3-ffvhuff420p12.out.rawvideo -stddev: 0.69 PSNR: 51.35 MAXDIFF: 1 bytes: 86700/ 86700 +a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth_lena-cinepak b/tests/ref/vsynth/vsynth_lena-cinepak index 39b1d6826..6b021673a 100644 --- a/tests/ref/vsynth/vsynth_lena-cinepak +++ b/tests/ref/vsynth/vsynth_lena-cinepak @@ -1,4 +1,4 @@ -e3837018f84929f07019ae2eccd303e2 *tests/data/fate/vsynth_lena-cinepak.mov -88900 tests/data/fate/vsynth_lena-cinepak.mov -f54ffa70f335ac7b701d7ae34462e001 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo -stddev: 4.09 PSNR: 35.88 MAXDIFF: 46 bytes: 7603200/ 456192 +a9ea19eb0d239a53af8630d5bc4167d0 *tests/data/fate/vsynth_lena-cinepak.avi +407574 tests/data/fate/vsynth_lena-cinepak.avi +e32d4103194665d2ea0f46d5cdd0cdf2 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo +stddev: 58.10 PSNR: 12.85 MAXDIFF: 185 bytes: 7603200/ 921600 diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 b/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 index e8ea4bcc8..e77698ba0 100644 --- a/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 @@ -1,4 +1,4 @@ b2f3d04ca30c113b79877bb5518dd6ea *tests/data/fate/vsynth_lena-ffvhuff420p12.avi 10925580 tests/data/fate/vsynth_lena-ffvhuff420p12.avi -08b3c6c70eba608bae926608ff253f2a *tests/data/fate/vsynth_lena-ffvhuff420p12.out.rawvideo -stddev: 0.68 PSNR: 51.38 MAXDIFF: 1 bytes: 7603200/ 7603200 +dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p10 b/tests/ref/vsynth/vsynth_lena-vc2-420p10 index 6428dd178..2558ef8e9 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p10 +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p10 @@ -1,4 +1,4 @@ 5bccec653c330f03b90065a84fad9b4b *tests/data/fate/vsynth_lena-vc2-420p10.mov 1154775 tests/data/fate/vsynth_lena-vc2-420p10.mov -32265ec286c54104b3be8f11c519da1b *tests/data/fate/vsynth_lena-vc2-420p10.out.rawvideo -stddev: 0.61 PSNR: 52.34 MAXDIFF: 1 bytes: 7603200/ 760320 +b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p10.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p12 b/tests/ref/vsynth/vsynth_lena-vc2-420p12 index e62b2b6d3..bc60116ff 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p12 +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p12 @@ -1,4 +1,4 @@ d27a6d3517cc9a6d22e338f4b206545c *tests/data/fate/vsynth_lena-vc2-420p12.mov 1516759 tests/data/fate/vsynth_lena-vc2-420p12.mov -bc62f1c3bade7224c55219dba8a3c6af *tests/data/fate/vsynth_lena-vc2-420p12.out.rawvideo -stddev: 0.68 PSNR: 51.39 MAXDIFF: 1 bytes: 7603200/ 760320 +b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 000000000..c0958f40c --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,19 @@ +/aviocat +/ffbisect +/bisect.need +/crypto_bench +/cws2fws +/fourcc2pixfmt +/ffescape +/ffeval +/ffhash +/graph2dot +/ismindex +/pktdumper +/probetest +/qt-faststart +/sidxindex +/trasher +/seek_print +/uncoded_frame +/zmqsend diff --git a/tools/aviocat.c b/tools/aviocat.c index 983108a64..28529b06d 100644 --- a/tools/aviocat.c +++ b/tools/aviocat.c @@ -107,6 +107,11 @@ int main(int argc, char **argv) if (n <= 0) break; avio_write(output, buf, n); + if (output->error) { + av_strerror(output->error, errbuf, sizeof(errbuf)); + fprintf(stderr, "Unable to write %s: %s\n", output_url, errbuf); + break; + } stream_pos += n; if (bps) { avio_flush(output); diff --git a/tools/bisect-create b/tools/bisect-create index fc60e8666..ee6ec3feb 100755 --- a/tools/bisect-create +++ b/tools/bisect-create @@ -20,7 +20,7 @@ fi case "$1" in need) case $2 in - ffmpeg|ffplay|ffprobe|ffserver) + ffmpeg|ffplay|ffprobe) echo $2.c >> tools/bisect.need ;; esac diff --git a/tools/cl2c b/tools/cl2c new file mode 100755 index 000000000..e3f92bab1 --- /dev/null +++ b/tools/cl2c @@ -0,0 +1,36 @@ +#!/bin/sh +# Convert an OpenCL source file into a C source file containing the +# OpenCL source as a C string. Also adds a #line directive so that +# compiler messages are useful. + +# This file is part of FFmpeg. +# +# FFmpeg is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# FFmpeg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with FFmpeg; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +input="$1" +output="$2" + +name=$(basename "$input" | sed 's/.cl$//') + +cat >$output <>$output + +echo ";" >>$output diff --git a/tools/patcheck b/tools/patcheck index 26137d6b2..101a542ff 100755 --- a/tools/patcheck +++ b/tools/patcheck @@ -68,7 +68,7 @@ $EGREP $OPT '^\+ *(const *|)static' $*| $EGREP --color=always '[^=]= *(0|NULL)[^ cat $TMP hiegrep '# *ifdef * (HAVE|CONFIG)_' 'ifdefs that should be #if' $* -hiegrep '\b(awnser|cant|dont|wont|doesnt|usefull|successfull|occured|teh|alot|wether|skiped|skiping|heigth|informations|colums|loosy|loosing|ouput|seperate|preceed|upto|paket|posible|unkown|inpossible|dimention|acheive|funtions|overriden|outputing|seperation|initalize|compatibilty|bistream|knwon|unknwon|choosen|additonal|gurantee|availble|wich|begining|milisecond|missmatch)\b' 'common typos' $* +hiegrep '\b(awnser|cant|dont|wont|doesnt|usefull|successfull|occured|teh|alot|wether|skiped|skiping|heigth|informations|colums|loosy|loosing|ouput|seperate|preceed|upto|paket|posible|unkown|inpossible|dimention|acheive|funtions|overriden|outputing|seperation|initalize|compatibilty|bistream|knwon|unknwon|choosen|additonal|gurantee|availble|wich|begining|milisecond|missmatch|threshhold)\b' 'common typos' $* hiegrep 'av_log\( *NULL' 'Missing context in av_log' $* hiegrep '[^sn]printf' 'Please use av_log' $* diff --git a/tools/qt-faststart.c b/tools/qt-faststart.c index 728f80c39..97be019c5 100644 --- a/tools/qt-faststart.c +++ b/tools/qt-faststart.c @@ -29,10 +29,7 @@ #include #include -#ifdef __MINGW32CE__ -#define fseeko(x, y, z) fseek(x, y, z) -#define ftello(x) ftell(x) -#elif defined(__MINGW32__) +#ifdef __MINGW32__ #undef fseeko #define fseeko(x, y, z) fseeko64(x, y, z) #undef ftello diff --git a/tools/target_dec_fuzzer.c b/tools/target_dec_fuzzer.c index a8696f9fc..62d62a9de 100644 --- a/tools/target_dec_fuzzer.c +++ b/tools/target_dec_fuzzer.c @@ -99,7 +99,7 @@ static void FDBCreate(FuzzDataBuffer *FDB) { static void FDBDesroy(FuzzDataBuffer *FDB) { av_free(FDB->data_); } static void FDBRealloc(FuzzDataBuffer *FDB, size_t size) { - size_t needed = size + FF_INPUT_BUFFER_PADDING_SIZE; + size_t needed = size + AV_INPUT_BUFFER_PADDING_SIZE; av_assert0(needed > size); if (needed > FDB->size_) { av_free(FDB->data_); @@ -116,8 +116,8 @@ static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data, FDBRealloc(FDB, size); memcpy(FDB->data_, data, size); size_t padd = FDB->size_ - size; - if (padd > FF_INPUT_BUFFER_PADDING_SIZE) - padd = FF_INPUT_BUFFER_PADDING_SIZE; + if (padd > AV_INPUT_BUFFER_PADDING_SIZE) + padd = AV_INPUT_BUFFER_PADDING_SIZE; memset(FDB->data_ + size, 0, padd); av_init_packet(dst); dst->data = FDB->data_; @@ -154,10 +154,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { av_log_set_level(AV_LOG_PANIC); } - // Unsupported - if (c->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - return 0; - switch (c->type) { case AVMEDIA_TYPE_AUDIO : decode_handler = avcodec_decode_audio4; break; case AVMEDIA_TYPE_VIDEO : decode_handler = avcodec_decode_video2; break; diff --git a/tools/uncoded_frame.c b/tools/uncoded_frame.c index 3ca2ba4bb..606bdb746 100644 --- a/tools/uncoded_frame.c +++ b/tools/uncoded_frame.c @@ -11,7 +11,6 @@ typedef struct { AVFormatContext *mux; AVStream *stream; AVFilterContext *sink; - AVFilterLink *link; } Stream; static int create_sink(Stream *st, AVFilterGraph *graph, @@ -36,7 +35,6 @@ static int create_sink(Stream *st, AVFilterGraph *graph, ret = avfilter_link(f, idx, st->sink, 0); if (ret < 0) return ret; - st->link = st->sink->inputs[0]; return 0; } @@ -163,26 +161,24 @@ int main(int argc, char **argv) av_log(NULL, AV_LOG_ERROR, "Failed to create output stream\n"); goto fail; } - st->stream->codec->codec_type = st->link->type; - st->stream->time_base = st->stream->codec->time_base = - st->link->time_base; - switch (st->link->type) { + st->stream->codecpar->codec_type = av_buffersink_get_type(st->sink); + st->stream->time_base = av_buffersink_get_time_base(st->sink); + switch (av_buffersink_get_type(st->sink)) { case AVMEDIA_TYPE_VIDEO: - st->stream->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + st->stream->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; st->stream->avg_frame_rate = st->stream-> r_frame_rate = av_buffersink_get_frame_rate(st->sink); - st->stream->codec->width = st->link->w; - st->stream->codec->height = st->link->h; - st->stream->codec->sample_aspect_ratio = st->link->sample_aspect_ratio; - st->stream->codec->pix_fmt = st->link->format; + st->stream->codecpar->width = av_buffersink_get_w(st->sink); + st->stream->codecpar->height = av_buffersink_get_h(st->sink); + st->stream->codecpar->sample_aspect_ratio = av_buffersink_get_sample_aspect_ratio(st->sink); + st->stream->codecpar->format = av_buffersink_get_format(st->sink); break; case AVMEDIA_TYPE_AUDIO: - st->stream->codec->channel_layout = st->link->channel_layout; - st->stream->codec->channels = avfilter_link_get_channels(st->link); - st->stream->codec->sample_rate = st->link->sample_rate; - st->stream->codec->sample_fmt = st->link->format; - st->stream->codec->codec_id = - av_get_pcm_codec(st->stream->codec->sample_fmt, -1); + st->stream->codecpar->channel_layout = av_buffersink_get_channel_layout(st->sink); + st->stream->codecpar->channels = av_buffersink_get_channels(st->sink); + st->stream->codecpar->sample_rate = av_buffersink_get_sample_rate(st->sink); + st->stream->codecpar->format = av_buffersink_get_format(st->sink); + st->stream->codecpar->codec_id = av_get_pcm_codec(st->stream->codecpar->format, -1); break; default: av_assert0(!"reached"); @@ -240,14 +236,14 @@ int main(int argc, char **argv) } if (frame->pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(frame->pts, - st->link ->time_base, + av_buffersink_get_time_base(st->sink), st->stream->time_base); ret = av_interleaved_write_uncoded_frame(st->mux, st->stream->index, frame); frame = NULL; if (ret < 0) { - av_log(st->stream->codec, AV_LOG_ERROR, + av_log(st->mux, AV_LOG_ERROR, "Error writing frame: %s\n", av_err2str(ret)); goto fail; }