diff options
Diffstat (limited to 'media/ffvpx/libavutil')
60 files changed, 2370 insertions, 423 deletions
diff --git a/media/ffvpx/libavutil/atomic_gcc.h b/media/ffvpx/libavutil/atomic_gcc.h index 5f9fc49ba0..2bb43c3cea 100644 --- a/media/ffvpx/libavutil/atomic_gcc.h +++ b/media/ffvpx/libavutil/atomic_gcc.h @@ -28,40 +28,27 @@ #define avpriv_atomic_int_get atomic_int_get_gcc static inline int atomic_int_get_gcc(volatile int *ptr) { -#if HAVE_ATOMIC_COMPARE_EXCHANGE - return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); -#else __sync_synchronize(); return *ptr; -#endif } #define avpriv_atomic_int_set atomic_int_set_gcc static inline void atomic_int_set_gcc(volatile int *ptr, int val) { -#if HAVE_ATOMIC_COMPARE_EXCHANGE - __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST); -#else *ptr = val; __sync_synchronize(); -#endif } #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) { -#if HAVE_ATOMIC_COMPARE_EXCHANGE - return __atomic_add_fetch(ptr, inc, __ATOMIC_SEQ_CST); -#else return __sync_add_and_fetch(ptr, inc); -#endif } #define avpriv_atomic_ptr_cas atomic_ptr_cas_gcc static inline void *atomic_ptr_cas_gcc(void * volatile *ptr, void *oldval, void *newval) { -#if HAVE_SYNC_VAL_COMPARE_AND_SWAP #ifdef __ARMCC_VERSION // armcc will throw an error if ptr is not an integer type volatile uintptr_t *tmp = (volatile uintptr_t*)ptr; @@ -69,10 +56,6 @@ static inline void *atomic_ptr_cas_gcc(void * volatile *ptr, #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif -#else - __atomic_compare_exchange_n(ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return oldval; -#endif } #endif /* AVUTIL_ATOMIC_GCC_H */ diff --git a/media/ffvpx/libavutil/attributes.h b/media/ffvpx/libavutil/attributes.h index 5c6b9deecb..54d1901116 100644 --- a/media/ffvpx/libavutil/attributes.h +++ b/media/ffvpx/libavutil/attributes.h @@ -121,8 +121,7 @@ #endif #endif - -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) # define av_unused __attribute__((unused)) #else # define av_unused @@ -133,7 +132,7 @@ * away. This is useful for variables accessed only from inline * assembler without the compiler being aware. */ -#if AV_GCC_VERSION_AT_LEAST(3,1) +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) # define av_used __attribute__((used)) #else # define av_used diff --git a/media/ffvpx/libavutil/avstring.c b/media/ffvpx/libavutil/avstring.c index 1787a1ef54..f03dd25141 100644 --- a/media/ffvpx/libavutil/avstring.c +++ b/media/ffvpx/libavutil/avstring.c @@ -231,6 +231,29 @@ int av_strncasecmp(const char *a, const char *b, size_t n) return c1 - c2; } +char *av_strireplace(const char *str, const char *from, const char *to) +{ + char *ret = NULL; + const char *pstr2, *pstr = str; + size_t tolen = strlen(to), fromlen = strlen(from); + AVBPrint pbuf; + + av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); + while ((pstr2 = av_stristr(pstr, from))) { + av_bprint_append_data(&pbuf, pstr, pstr2 - pstr); + pstr = pstr2 + fromlen; + av_bprint_append_data(&pbuf, to, tolen); + } + av_bprint_append_data(&pbuf, pstr, strlen(pstr)); + if (!av_bprint_is_complete(&pbuf)) { + av_bprint_finalize(&pbuf, NULL); + } else { + av_bprint_finalize(&pbuf, &ret); + } + + return ret; +} + const char *av_basename(const char *path) { char *p = strrchr(path, '/'); diff --git a/media/ffvpx/libavutil/avstring.h b/media/ffvpx/libavutil/avstring.h index dd2876990f..04d2695640 100644 --- a/media/ffvpx/libavutil/avstring.h +++ b/media/ffvpx/libavutil/avstring.h @@ -266,6 +266,11 @@ int av_strcasecmp(const char *a, const char *b); */ int av_strncasecmp(const char *a, const char *b, size_t n); +/** + * Locale-independent strings replace. + * @note This means only ASCII-range characters are replace + */ +char *av_strireplace(const char *str, const char *from, const char *to); /** * Thread safe basename. diff --git a/media/ffvpx/libavutil/avutil.h b/media/ffvpx/libavutil/avutil.h index 29dd830bf5..4d633156d1 100644 --- a/media/ffvpx/libavutil/avutil.h +++ b/media/ffvpx/libavutil/avutil.h @@ -118,6 +118,12 @@ * * @} * + * @defgroup lavu_video Video related + * + * @{ + * + * @} + * * @defgroup lavu_audio Audio related * * @{ @@ -337,6 +343,20 @@ FILE *av_fopen_utf8(const char *path, const char *mode); */ AVRational av_get_time_base_q(void); +#define AV_FOURCC_MAX_STRING_SIZE 32 + +#define av_fourcc2str(fourcc) av_fourcc_make_string((char[AV_FOURCC_MAX_STRING_SIZE]){0}, fourcc) + +/** + * Fill the provided buffer with a string containing a FourCC (four-character + * code) representation. + * + * @param buf a buffer with size in bytes of at least AV_FOURCC_MAX_STRING_SIZE + * @param fourcc the fourcc to represent + * @return the buffer in input + */ +char *av_fourcc_make_string(char *buf, uint32_t fourcc); + /** * @} * @} diff --git a/media/ffvpx/libavutil/avutil.symbols b/media/ffvpx/libavutil/avutil.symbols index 81cf6a8ef3..fb93143faf 100644 --- a/media/ffvpx/libavutil/avutil.symbols +++ b/media/ffvpx/libavutil/avutil.symbols @@ -88,7 +88,9 @@ av_find_best_pix_fmt_of_2 av_find_info_tag av_find_nearest_q_idx av_force_cpu_flags +av_fourcc_make_string av_frame_alloc +av_frame_apply_cropping av_frame_clone av_frame_copy av_frame_copy_props @@ -166,6 +168,7 @@ av_hwframe_get_buffer av_image_alloc av_image_check_sar av_image_check_size +av_image_check_size2 av_image_copy av_image_copy_plane av_image_copy_to_buffer @@ -332,5 +335,8 @@ avutil_configuration avutil_license avutil_version #ifdef XP_WIN -avpriv_emms_yasm +avpriv_emms_asm #endif +avpriv_slicethread_create +avpriv_slicethread_execute +avpriv_slicethread_free diff --git a/media/ffvpx/libavutil/buffer.c b/media/ffvpx/libavutil/buffer.c index 694e116a3c..8d1aa5fa84 100644 --- a/media/ffvpx/libavutil/buffer.c +++ b/media/ffvpx/libavutil/buffer.c @@ -16,10 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdatomic.h> #include <stdint.h> #include <string.h> -#include "atomic.h" #include "buffer_internal.h" #include "common.h" #include "mem.h" @@ -40,7 +40,8 @@ AVBufferRef *av_buffer_create(uint8_t *data, int size, buf->size = size; buf->free = free ? free : av_buffer_default_free; buf->opaque = opaque; - buf->refcount = 1; + + atomic_init(&buf->refcount, 1); if (flags & AV_BUFFER_FLAG_READONLY) buf->flags |= BUFFER_FLAG_READONLY; @@ -98,7 +99,7 @@ AVBufferRef *av_buffer_ref(AVBufferRef *buf) *ret = *buf; - avpriv_atomic_int_add_and_fetch(&buf->buffer->refcount, 1); + atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed); return ret; } @@ -115,7 +116,7 @@ static void buffer_replace(AVBufferRef **dst, AVBufferRef **src) } else av_freep(dst); - if (!avpriv_atomic_int_add_and_fetch(&b->refcount, -1)) { + if (atomic_fetch_add_explicit(&b->refcount, -1, memory_order_acq_rel) == 1) { b->free(b->opaque, b->data); av_freep(&b); } @@ -134,7 +135,7 @@ int av_buffer_is_writable(const AVBufferRef *buf) if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY) return 0; - return avpriv_atomic_int_get(&buf->buffer->refcount) == 1; + return atomic_load(&buf->buffer->refcount) == 1; } void *av_buffer_get_opaque(const AVBufferRef *buf) @@ -144,7 +145,7 @@ void *av_buffer_get_opaque(const AVBufferRef *buf) int av_buffer_get_ref_count(const AVBufferRef *buf) { - return buf->buffer->refcount; + return atomic_load(&buf->buffer->refcount); } int av_buffer_make_writable(AVBufferRef **pbuf) @@ -191,7 +192,7 @@ int av_buffer_realloc(AVBufferRef **pbuf, int size) return 0; if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) || - !av_buffer_is_writable(buf)) { + !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) { /* cannot realloc, allocate a new reallocable buffer and copy data */ AVBufferRef *new = NULL; @@ -229,7 +230,7 @@ AVBufferPool *av_buffer_pool_init2(int size, void *opaque, pool->alloc2 = alloc; pool->pool_free = pool_free; - avpriv_atomic_int_set(&pool->refcount, 1); + atomic_init(&pool->refcount, 1); return pool; } @@ -245,7 +246,7 @@ AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)) pool->size = size; pool->alloc = alloc ? alloc : av_buffer_alloc; - avpriv_atomic_int_set(&pool->refcount, 1); + atomic_init(&pool->refcount, 1); return pool; } @@ -280,48 +281,10 @@ void av_buffer_pool_uninit(AVBufferPool **ppool) pool = *ppool; *ppool = NULL; - if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1)) + if (atomic_fetch_add_explicit(&pool->refcount, -1, memory_order_acq_rel) == 1) buffer_pool_free(pool); } -#if USE_ATOMICS -/* remove the whole buffer list from the pool and return it */ -static BufferPoolEntry *get_pool(AVBufferPool *pool) -{ - BufferPoolEntry *cur = *(void * volatile *)&pool->pool, *last = NULL; - - while (cur != last) { - last = cur; - cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL); - if (!cur) - return NULL; - } - - return cur; -} - -static void add_to_pool(BufferPoolEntry *buf) -{ - AVBufferPool *pool; - BufferPoolEntry *cur, *end = buf; - - if (!buf) - return; - pool = buf->pool; - - while (end->next) - end = end->next; - - while (avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf)) { - /* pool is not empty, retrieve it and append it to our list */ - cur = get_pool(pool); - end->next = cur; - while (end->next) - end = end->next; - } -} -#endif - static void pool_release_buffer(void *opaque, uint8_t *data) { BufferPoolEntry *buf = opaque; @@ -330,16 +293,12 @@ static void pool_release_buffer(void *opaque, uint8_t *data) if(CONFIG_MEMORY_POISONING) memset(buf->data, FF_MEMORY_POISON, pool->size); -#if USE_ATOMICS - add_to_pool(buf); -#else ff_mutex_lock(&pool->mutex); buf->next = pool->pool; pool->pool = buf; ff_mutex_unlock(&pool->mutex); -#endif - if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1)) + if (atomic_fetch_add_explicit(&pool->refcount, -1, memory_order_acq_rel) == 1) buffer_pool_free(pool); } @@ -369,11 +328,6 @@ static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool) ret->buffer->opaque = buf; ret->buffer->free = pool_release_buffer; -#if USE_ATOMICS - avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); - avpriv_atomic_int_add_and_fetch(&pool->nb_allocated, 1); -#endif - return ret; } @@ -382,29 +336,6 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) AVBufferRef *ret; BufferPoolEntry *buf; -#if USE_ATOMICS - /* check whether the pool is empty */ - buf = get_pool(pool); - if (!buf && pool->refcount <= pool->nb_allocated) { - av_log(NULL, AV_LOG_DEBUG, "Pool race dectected, spining to avoid overallocation and eventual OOM\n"); - while (!buf && avpriv_atomic_int_get(&pool->refcount) <= avpriv_atomic_int_get(&pool->nb_allocated)) - buf = get_pool(pool); - } - - if (!buf) - return pool_alloc_buffer(pool); - - /* keep the first entry, return the rest of the list to the pool */ - add_to_pool(buf->next); - buf->next = NULL; - - ret = av_buffer_create(buf->data, pool->size, pool_release_buffer, - buf, 0); - if (!ret) { - add_to_pool(buf); - return NULL; - } -#else ff_mutex_lock(&pool->mutex); buf = pool->pool; if (buf) { @@ -418,10 +349,9 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) ret = pool_alloc_buffer(pool); } ff_mutex_unlock(&pool->mutex); -#endif if (ret) - avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); + atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed); return ret; } diff --git a/media/ffvpx/libavutil/buffer.h b/media/ffvpx/libavutil/buffer.h index 0c0ce12cf2..73b6bd0b14 100644 --- a/media/ffvpx/libavutil/buffer.h +++ b/media/ffvpx/libavutil/buffer.h @@ -256,9 +256,10 @@ AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); * @param alloc a function that will be used to allocate new buffers when the * pool is empty. * @param pool_free a function that will be called immediately before the pool - * is freed. I.e. after av_buffer_pool_can_uninit() is called - * by the pool and all the frames are returned to the pool and - * freed. It is intended to uninitialize the user opaque data. + * is freed. I.e. after av_buffer_pool_uninit() is called + * by the caller and all the frames are returned to the pool + * and freed. It is intended to uninitialize the user opaque + * data. * @return newly created buffer pool on success, NULL on error. */ AVBufferPool *av_buffer_pool_init2(int size, void *opaque, diff --git a/media/ffvpx/libavutil/buffer_internal.h b/media/ffvpx/libavutil/buffer_internal.h index 29ce8a643c..54b67047e5 100644 --- a/media/ffvpx/libavutil/buffer_internal.h +++ b/media/ffvpx/libavutil/buffer_internal.h @@ -19,6 +19,7 @@ #ifndef AVUTIL_BUFFER_INTERNAL_H #define AVUTIL_BUFFER_INTERNAL_H +#include <stdatomic.h> #include <stdint.h> #include "buffer.h" @@ -40,7 +41,7 @@ struct AVBuffer { /** * number of existing AVBufferRef instances referring to this buffer */ - volatile int refcount; + atomic_uint refcount; /** * a callback for freeing the data @@ -85,9 +86,7 @@ struct AVBufferPool { * buffers have been released, then it's safe to free the pool and all * the buffers in it. */ - volatile int refcount; - - volatile int nb_allocated; + atomic_uint refcount; int size; void *opaque; diff --git a/media/ffvpx/libavutil/channel_layout.c b/media/ffvpx/libavutil/channel_layout.c index 26c87c96a8..3bd5ee29b7 100644 --- a/media/ffvpx/libavutil/channel_layout.c +++ b/media/ffvpx/libavutil/channel_layout.c @@ -152,6 +152,28 @@ uint64_t av_get_channel_layout(const char *name) return layout; } +int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels) +{ + int nb = 0; + char *end; + uint64_t layout = av_get_channel_layout(name); + + if (layout) { + *channel_layout = layout; + *nb_channels = av_get_channel_layout_nb_channels(layout); + return 0; + } + + nb = strtol(name, &end, 10); + if (!errno && *end == 'C' && *(end + 1) == '\0' && nb > 0 && nb < 64) { + *channel_layout = 0; + *nb_channels = nb; + return 0; + } + + return AVERROR(EINVAL); +} + void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout) { diff --git a/media/ffvpx/libavutil/channel_layout.h b/media/ffvpx/libavutil/channel_layout.h index ec7effead1..50bb8f03c5 100644 --- a/media/ffvpx/libavutil/channel_layout.h +++ b/media/ffvpx/libavutil/channel_layout.h @@ -131,22 +131,31 @@ enum AVMatrixEncoding { * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); - * - a number of channels, in decimal, optionally followed by 'c', yielding + * - a number of channels, in decimal, followed by 'c', yielding * the default channel layout for that number of channels (@see * av_get_default_channel_layout); * - a channel layout mask, in hexadecimal starting with "0x" (see the * AV_CH_* macros). * - * @warning Starting from the next major bump the trailing character - * 'c' to specify a number of channels will be required, while a - * channel layout mask could also be specified as a decimal number - * (if and only if not followed by "c"). - * * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" */ uint64_t av_get_channel_layout(const char *name); /** + * Return a channel layout and the number of channels based on the specified name. + * + * This function is similar to (@see av_get_channel_layout), but can also parse + * unknown channel layout specifications. + * + * @param[in] name channel layout specification string + * @param[out] channel_layout parsed channel layout (0 if unknown) + * @param[out] nb_channels number of channels + * + * @return 0 on success, AVERROR(EINVAL) if the parsing fails. + */ +int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels); + +/** * Return a description of a channel layout. * If nb_channels is <= 0, it is guessed from the channel_layout. * diff --git a/media/ffvpx/libavutil/cpu.c b/media/ffvpx/libavutil/cpu.c index f5785fc13f..c8401b8258 100644 --- a/media/ffvpx/libavutil/cpu.c +++ b/media/ffvpx/libavutil/cpu.c @@ -16,8 +16,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stddef.h> #include <stdint.h> +#include <stdatomic.h> +#include "attributes.h" #include "cpu.h" #include "cpu_internal.h" #include "config.h" @@ -44,10 +47,24 @@ #include <unistd.h> #endif -static int flags, checked; +static atomic_int cpu_flags = ATOMIC_VAR_INIT(-1); + +static int get_cpu_flags(void) +{ + if (ARCH_AARCH64) + return ff_get_cpu_flags_aarch64(); + if (ARCH_ARM) + return ff_get_cpu_flags_arm(); + if (ARCH_PPC) + return ff_get_cpu_flags_ppc(); + if (ARCH_X86) + return ff_get_cpu_flags_x86(); + return 0; +} void av_force_cpu_flags(int arg){ - if ( (arg & ( AV_CPU_FLAG_3DNOW | + if (ARCH_X86 && + (arg & ( AV_CPU_FLAG_3DNOW | AV_CPU_FLAG_3DNOWEXT | AV_CPU_FLAG_MMXEXT | AV_CPU_FLAG_SSE | @@ -69,33 +86,23 @@ void av_force_cpu_flags(int arg){ arg |= AV_CPU_FLAG_MMX; } - flags = arg; - checked = arg != -1; + atomic_store_explicit(&cpu_flags, arg, memory_order_relaxed); } int av_get_cpu_flags(void) { - if (checked) - return flags; - - if (ARCH_AARCH64) - flags = ff_get_cpu_flags_aarch64(); - if (ARCH_ARM) - flags = ff_get_cpu_flags_arm(); - if (ARCH_PPC) - flags = ff_get_cpu_flags_ppc(); - if (ARCH_X86) - flags = ff_get_cpu_flags_x86(); - - checked = 1; + int flags = atomic_load_explicit(&cpu_flags, memory_order_relaxed); + if (flags == -1) { + flags = get_cpu_flags(); + atomic_store_explicit(&cpu_flags, flags, memory_order_relaxed); + } return flags; } void av_set_cpu_flags_mask(int mask) { - checked = 0; - flags = av_get_cpu_flags() & mask; - checked = 1; + atomic_store_explicit(&cpu_flags, get_cpu_flags() & mask, + memory_order_relaxed); } int av_parse_cpu_flags(const char *s) @@ -294,3 +301,17 @@ int av_cpu_count(void) return nb_cpus; } + +size_t av_cpu_max_align(void) +{ + if (ARCH_AARCH64) + return ff_get_cpu_max_align_aarch64(); + if (ARCH_ARM) + return ff_get_cpu_max_align_arm(); + if (ARCH_PPC) + return ff_get_cpu_max_align_ppc(); + if (ARCH_X86) + return ff_get_cpu_max_align_x86(); + + return 8; +} diff --git a/media/ffvpx/libavutil/cpu.h b/media/ffvpx/libavutil/cpu.h index 4bff16714a..9e5d40affe 100644 --- a/media/ffvpx/libavutil/cpu.h +++ b/media/ffvpx/libavutil/cpu.h @@ -21,6 +21,8 @@ #ifndef AVUTIL_CPU_H #define AVUTIL_CPU_H +#include <stddef.h> + #include "attributes.h" #define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ @@ -39,6 +41,7 @@ #define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster ///< than regular MMX/SSE (e.g. Core1) #define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_SSSE3SLOW 0x4000000 ///< SSSE3 supported, but usually not faster #define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower #define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions #define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions @@ -85,8 +88,6 @@ void av_force_cpu_flags(int flags); * Set a mask on flags returned by av_get_cpu_flags(). * This function is mainly useful for testing. * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible - * - * @warning this function is not thread safe. */ attribute_deprecated void av_set_cpu_flags_mask(int mask); @@ -114,4 +115,15 @@ int av_parse_cpu_caps(unsigned *flags, const char *s); */ int av_cpu_count(void); +/** + * Get the maximum data alignment that may be required by FFmpeg. + * + * Note that this is affected by the build configuration and the CPU flags mask, + * so e.g. if the CPU supports AVX, but libavutil has been built with + * --disable-avx or the AV_CPU_FLAG_AVX flag has been disabled through + * av_set_cpu_flags_mask(), then this function will behave as if AVX is not + * present. + */ +size_t av_cpu_max_align(void); + #endif /* AVUTIL_CPU_H */ diff --git a/media/ffvpx/libavutil/cpu_internal.h b/media/ffvpx/libavutil/cpu_internal.h index 6c352abe1b..b8bf1e5396 100644 --- a/media/ffvpx/libavutil/cpu_internal.h +++ b/media/ffvpx/libavutil/cpu_internal.h @@ -44,4 +44,9 @@ int ff_get_cpu_flags_arm(void); int ff_get_cpu_flags_ppc(void); int ff_get_cpu_flags_x86(void); +size_t ff_get_cpu_max_align_aarch64(void); +size_t ff_get_cpu_max_align_arm(void); +size_t ff_get_cpu_max_align_ppc(void); +size_t ff_get_cpu_max_align_x86(void); + #endif /* AVUTIL_CPU_INTERNAL_H */ diff --git a/media/ffvpx/libavutil/display.h b/media/ffvpx/libavutil/display.h index 39c15ee6b8..515adad795 100644 --- a/media/ffvpx/libavutil/display.h +++ b/media/ffvpx/libavutil/display.h @@ -18,6 +18,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/** + * @file + * Display matrix + */ + #ifndef AVUTIL_DISPLAY_H #define AVUTIL_DISPLAY_H @@ -25,15 +30,26 @@ #include "common.h" /** + * @addtogroup lavu_video + * @{ + * + * @defgroup lavu_video_display Display transformation matrix functions + * @{ + */ + +/** + * @addtogroup lavu_video_display * The display transformation matrix specifies an affine transformation that * should be applied to video frames for correct presentation. It is compatible * with the matrices stored in the ISO/IEC 14496-12 container format. * * The data is a 3x3 matrix represented as a 9-element array: * + * @code{.unparsed} * | a b u | * (a, b, u, c, d, v, x, y, w) -> | c d v | * | x y w | + * @endcode * * All numbers are stored in native endianness, as 16.16 fixed-point values, * except for u, v and w, which are stored as 2.30 fixed-point values. @@ -41,15 +57,21 @@ * The transformation maps a point (p, q) in the source (pre-transformation) * frame to the point (p', q') in the destination (post-transformation) frame as * follows: + * + * @code{.unparsed} * | a b u | * (p, q, 1) . | c d v | = z * (p', q', 1) * | x y w | + * @endcode * * The transformation can also be more explicitly written in components as * follows: + * + * @code{.unparsed} * p' = (a * p + c * q + x) / z; * q' = (b * p + d * q + y) / z; * z = u * p + v * q + w + * @endcode */ /** @@ -84,4 +106,9 @@ void av_display_rotation_set(int32_t matrix[9], double angle); */ void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); +/** + * @} + * @} + */ + #endif /* AVUTIL_DISPLAY_H */ diff --git a/media/ffvpx/libavutil/dummy_funcs.c b/media/ffvpx/libavutil/dummy_funcs.c index e579fcc893..3a2381074b 100644 --- a/media/ffvpx/libavutil/dummy_funcs.c +++ b/media/ffvpx/libavutil/dummy_funcs.c @@ -19,3 +19,8 @@ void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict) {} void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp) {} int av_hwframe_get_buffer(struct AVBufferRef* hwframe_ref, struct AVFrame* frame, int flags) { return 0; } + +// cpu.c +size_t ff_get_cpu_max_align_aarch64() { return 0; } +size_t ff_get_cpu_max_align_arm() { return 0; } +size_t ff_get_cpu_max_align_ppc() { return 0; } diff --git a/media/ffvpx/libavutil/eval.c b/media/ffvpx/libavutil/eval.c index fc12885c27..e5948793bd 100644 --- a/media/ffvpx/libavutil/eval.c +++ b/media/ffvpx/libavutil/eval.c @@ -38,6 +38,7 @@ #include "fftime.h" #include "avstring.h" #include "timer.h" +#include "reverse.h" typedef struct Parser { const AVClass *class; @@ -152,9 +153,9 @@ struct AVExpr { e_squish, e_gauss, e_ld, e_isnan, e_isinf, e_mod, e_max, e_min, e_eq, e_gt, e_gte, e_lte, e_lt, e_pow, e_mul, e_div, e_add, - e_last, e_st, e_while, e_taylor, e_root, e_floor, e_ceil, e_trunc, + e_last, e_st, e_while, e_taylor, e_root, e_floor, e_ceil, e_trunc, e_round, e_sqrt, e_not, e_random, e_hypot, e_gcd, - e_if, e_ifnot, e_print, e_bitand, e_bitor, e_between, e_clip + e_if, e_ifnot, e_print, e_bitand, e_bitor, e_between, e_clip, e_atan2, e_lerp, } type; double value; // is sign in other types union { @@ -188,6 +189,7 @@ static double eval_expr(Parser *p, AVExpr *e) case e_floor: return e->value * floor(eval_expr(p, e->param[0])); case e_ceil : return e->value * ceil (eval_expr(p, e->param[0])); case e_trunc: return e->value * trunc(eval_expr(p, e->param[0])); + case e_round: return e->value * round(eval_expr(p, e->param[0])); case e_sqrt: return e->value * sqrt (eval_expr(p, e->param[0])); case e_not: return e->value * (eval_expr(p, e->param[0]) == 0); case e_if: return e->value * (eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) : @@ -206,6 +208,12 @@ static double eval_expr(Parser *p, AVExpr *e) return e->value * (d >= eval_expr(p, e->param[1]) && d <= eval_expr(p, e->param[2])); } + case e_lerp: { + double v0 = eval_expr(p, e->param[0]); + double v1 = eval_expr(p, e->param[1]); + double f = eval_expr(p, e->param[2]); + return v0 + (v1 - v0) * f; + } case e_print: { double x = eval_expr(p, e->param[0]); int level = e->param[1] ? av_clip(eval_expr(p, e->param[1]), INT_MIN, INT_MAX) : AV_LOG_INFO; @@ -305,6 +313,7 @@ static double eval_expr(Parser *p, AVExpr *e) case e_last:return e->value * d2; case e_st : return e->value * (p->var[av_clip(d, 0, VARS-1)]= d2); case e_hypot:return e->value * hypot(d, d2); + case e_atan2:return e->value * atan2(d, d2); case e_bitand: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d & (long int)d2); case e_bitor: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d | (long int)d2); } @@ -438,6 +447,7 @@ static int parse_primary(AVExpr **e, Parser *p) else if (strmatch(next, "floor" )) d->type = e_floor; else if (strmatch(next, "ceil" )) d->type = e_ceil; else if (strmatch(next, "trunc" )) d->type = e_trunc; + else if (strmatch(next, "round" )) d->type = e_round; else if (strmatch(next, "sqrt" )) d->type = e_sqrt; else if (strmatch(next, "not" )) d->type = e_not; else if (strmatch(next, "pow" )) d->type = e_pow; @@ -451,6 +461,8 @@ static int parse_primary(AVExpr **e, Parser *p) else if (strmatch(next, "bitor" )) d->type = e_bitor; else if (strmatch(next, "between"))d->type = e_between; else if (strmatch(next, "clip" )) d->type = e_clip; + else if (strmatch(next, "atan2" )) d->type = e_atan2; + else if (strmatch(next, "lerp" )) d->type = e_lerp; else { for (i=0; p->func1_names && p->func1_names[i]; i++) { if (strmatch(next, p->func1_names[i])) { @@ -634,6 +646,7 @@ static int verify_expr(AVExpr *e) case e_floor: case e_ceil: case e_trunc: + case e_round: case e_sqrt: case e_not: case e_random: @@ -648,6 +661,7 @@ static int verify_expr(AVExpr *e) && (!e->param[2] || verify_expr(e->param[2])); case e_between: case e_clip: + case e_lerp: return verify_expr(e->param[0]) && verify_expr(e->param[1]) && verify_expr(e->param[2]); diff --git a/media/ffvpx/libavutil/float_dsp.c b/media/ffvpx/libavutil/float_dsp.c index c85daffc6a..1d4911d815 100644 --- a/media/ffvpx/libavutil/float_dsp.c +++ b/media/ffvpx/libavutil/float_dsp.c @@ -40,6 +40,14 @@ static void vector_fmac_scalar_c(float *dst, const float *src, float mul, dst[i] += src[i] * mul; } +static void vector_dmac_scalar_c(double *dst, const double *src, double mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] += src[i] * mul; +} + static void vector_fmul_scalar_c(float *dst, const float *src, float mul, int len) { @@ -125,6 +133,7 @@ av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) fdsp->vector_fmul = vector_fmul_c; fdsp->vector_fmac_scalar = vector_fmac_scalar_c; fdsp->vector_fmul_scalar = vector_fmul_scalar_c; + fdsp->vector_dmac_scalar = vector_dmac_scalar_c; fdsp->vector_dmul_scalar = vector_dmul_scalar_c; fdsp->vector_fmul_window = vector_fmul_window_c; fdsp->vector_fmul_add = vector_fmul_add_c; diff --git a/media/ffvpx/libavutil/float_dsp.h b/media/ffvpx/libavutil/float_dsp.h index d1be38f947..2c24d93471 100644 --- a/media/ffvpx/libavutil/float_dsp.h +++ b/media/ffvpx/libavutil/float_dsp.h @@ -55,6 +55,22 @@ typedef struct AVFloatDSPContext { int len); /** + * Multiply a vector of doubles by a scalar double and add to + * destination vector. Source and destination vectors must + * overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 16 + */ + void (*vector_dmac_scalar)(double *dst, const double *src, double mul, + int len); + + /** * Multiply a vector of floats by a scalar float. Source and * destination vectors must overlap exactly or not at all. * diff --git a/media/ffvpx/libavutil/frame.c b/media/ffvpx/libavutil/frame.c index 53e6174223..d5fd2932e3 100644 --- a/media/ffvpx/libavutil/frame.c +++ b/media/ffvpx/libavutil/frame.c @@ -26,6 +26,11 @@ #include "mem.h" #include "samplefmt.h" + +static AVFrameSideData *frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf); + 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) @@ -176,6 +181,9 @@ static int get_video_buffer(AVFrame *frame, int align) return ret; if (!frame->linesize[0]) { + if (align <= 0) + align = 32; /* STRIDE_ALIGN. Should be av_cpu_max_align() */ + for(i=1; i<=align; i+=i) { ret = av_image_fill_linesizes(frame->linesize, frame->format, FFALIGN(frame->width, i)); @@ -292,6 +300,10 @@ static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy) dst->key_frame = src->key_frame; dst->pict_type = src->pict_type; dst->sample_aspect_ratio = src->sample_aspect_ratio; + dst->crop_top = src->crop_top; + dst->crop_bottom = src->crop_bottom; + dst->crop_left = src->crop_left; + dst->crop_right = src->crop_right; dst->pts = src->pts; dst->repeat_pict = src->repeat_pict; dst->interlaced_frame = src->interlaced_frame; @@ -344,18 +356,11 @@ FF_ENABLE_DEPRECATION_WARNINGS } memcpy(sd_dst->data, sd_src->data, sd_src->size); } else { - sd_dst = av_frame_new_side_data(dst, sd_src->type, 0); + sd_dst = frame_new_side_data(dst, sd_src->type, av_buffer_ref(sd_src->buf)); if (!sd_dst) { wipe_side_data(dst); return AVERROR(ENOMEM); } - sd_dst->buf = av_buffer_ref(sd_src->buf); - if (!sd_dst->buf) { - wipe_side_data(dst); - return AVERROR(ENOMEM); - } - sd_dst->data = sd_dst->buf->data; - sd_dst->size = sd_dst->buf->size; } av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0); } @@ -377,6 +382,13 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif + av_buffer_unref(&dst->opaque_ref); + if (src->opaque_ref) { + dst->opaque_ref = av_buffer_ref(src->opaque_ref); + if (!dst->opaque_ref) + return AVERROR(ENOMEM); + } + return 0; } @@ -511,6 +523,8 @@ void av_frame_unref(AVFrame *frame) av_buffer_unref(&frame->hw_frames_ctx); + av_buffer_unref(&frame->opaque_ref); + get_frame_defaults(frame); } @@ -622,40 +636,47 @@ AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane) return NULL; } -AVFrameSideData *av_frame_new_side_data(AVFrame *frame, - enum AVFrameSideDataType type, - int size) +static AVFrameSideData *frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf) { AVFrameSideData *ret, **tmp; - if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1) + if (!buf) return NULL; + if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1) + goto fail; + tmp = av_realloc(frame->side_data, (frame->nb_side_data + 1) * sizeof(*frame->side_data)); if (!tmp) - return NULL; + goto fail; frame->side_data = tmp; ret = av_mallocz(sizeof(*ret)); if (!ret) - return NULL; + goto fail; - if (size > 0) { - ret->buf = av_buffer_alloc(size); - if (!ret->buf) { - av_freep(&ret); - return NULL; - } - - ret->data = ret->buf->data; - ret->size = size; - } + ret->buf = buf; + ret->data = ret->buf->data; + ret->size = buf->size; ret->type = type; frame->side_data[frame->nb_side_data++] = ret; return ret; +fail: + av_buffer_unref(&buf); + return NULL; +} + +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size) +{ + + return frame_new_side_data(frame, type, av_buffer_alloc(size)); } AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, @@ -723,7 +744,7 @@ int av_frame_copy(AVFrame *dst, const AVFrame *src) if (dst->width > 0 && dst->height > 0) return frame_copy_video(dst, src); - else if (dst->nb_samples > 0 && dst->channel_layout) + else if (dst->nb_samples > 0 && dst->channels > 0) return frame_copy_audio(dst, src); return AVERROR(EINVAL); @@ -758,7 +779,109 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type) case AV_FRAME_DATA_SKIP_SAMPLES: return "Skip samples"; case AV_FRAME_DATA_AUDIO_SERVICE_TYPE: return "Audio service type"; case AV_FRAME_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata"; + case AV_FRAME_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata"; case AV_FRAME_DATA_GOP_TIMECODE: return "GOP timecode"; + case AV_FRAME_DATA_ICC_PROFILE: return "ICC profile"; } return NULL; } + +static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, + const AVPixFmtDescriptor *desc) +{ + int i, j; + + for (i = 0; frame->data[i]; i++) { + const AVComponentDescriptor *comp = NULL; + int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0; + int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL) && i == 1) { + offsets[i] = 0; + break; + } + + /* find any component descriptor for this plane */ + for (j = 0; j < desc->nb_components; j++) { + if (desc->comp[j].plane == i) { + comp = &desc->comp[j]; + break; + } + } + if (!comp) + return AVERROR_BUG; + + offsets[i] = (frame->crop_top >> shift_y) * frame->linesize[i] + + (frame->crop_left >> shift_x) * comp->step; + } + + return 0; +} + +int av_frame_apply_cropping(AVFrame *frame, int flags) +{ + const AVPixFmtDescriptor *desc; + size_t offsets[4]; + int i; + + if (!(frame->width > 0 && frame->height > 0)) + return AVERROR(EINVAL); + + if (frame->crop_left >= INT_MAX - frame->crop_right || + frame->crop_top >= INT_MAX - frame->crop_bottom || + (frame->crop_left + frame->crop_right) >= frame->width || + (frame->crop_top + frame->crop_bottom) >= frame->height) + return AVERROR(ERANGE); + + desc = av_pix_fmt_desc_get(frame->format); + if (!desc) + return AVERROR_BUG; + + /* Apply just the right/bottom cropping for hwaccel formats. Bitstream + * formats cannot be easily handled here either (and corresponding decoders + * should not export any cropping anyway), so do the same for those as well. + * */ + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) { + frame->width -= frame->crop_right; + frame->height -= frame->crop_bottom; + frame->crop_right = 0; + frame->crop_bottom = 0; + return 0; + } + + /* calculate the offsets for each plane */ + calc_cropping_offsets(offsets, frame, desc); + + /* adjust the offsets to avoid breaking alignment */ + if (!(flags & AV_FRAME_CROP_UNALIGNED)) { + int log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) : INT_MAX; + int min_log2_align = INT_MAX; + + for (i = 0; frame->data[i]; i++) { + int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; + min_log2_align = FFMIN(log2_align, min_log2_align); + } + + /* we assume, and it should always be true, that the data alignment is + * related to the cropping alignment by a constant power-of-2 factor */ + if (log2_crop_align < min_log2_align) + return AVERROR_BUG; + + if (min_log2_align < 5) { + frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1); + calc_cropping_offsets(offsets, frame, desc); + } + } + + for (i = 0; frame->data[i]; i++) + frame->data[i] += offsets[i]; + + frame->width -= (frame->crop_left + frame->crop_right); + frame->height -= (frame->crop_top + frame->crop_bottom); + frame->crop_left = 0; + frame->crop_right = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + + return 0; +} diff --git a/media/ffvpx/libavutil/frame.h b/media/ffvpx/libavutil/frame.h index 8e51361e29..abe4f4fd17 100644 --- a/media/ffvpx/libavutil/frame.h +++ b/media/ffvpx/libavutil/frame.h @@ -25,6 +25,7 @@ #ifndef AVUTIL_FRAME_H #define AVUTIL_FRAME_H +#include <stddef.h> #include <stdint.h> #include "avutil.h" @@ -120,7 +121,26 @@ enum AVFrameSideDataType { * The GOP timecode in 25 bit timecode format. Data format is 64-bit integer. * This is set on the first frame of a GOP that has a temporal reference of 0. */ - AV_FRAME_DATA_GOP_TIMECODE + AV_FRAME_DATA_GOP_TIMECODE, + + /** + * The data represents the AVSphericalMapping structure defined in + * libavutil/spherical.h. + */ + AV_FRAME_DATA_SPHERICAL, + + /** + * Content light level (based on CTA-861.3). This payload contains data in + * the form of the AVContentLightMetadata struct. + */ + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + + /** + * The data contains an ICC profile as an opaque octet buffer following the + * format described by ISO 15076-1 with an optional name defined in the + * metadata key entry "name". + */ + AV_FRAME_DATA_ICC_PROFILE, }; enum AVActiveFormatDescription { @@ -173,9 +193,6 @@ typedef struct AVFrameSideData { * * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added * to the end with a minor bump. - * Similarly fields that are marked as to be only accessed by - * av_opt_ptr() can be reordered. This allows 2 forks to add fields - * without breaking compatibility with each other. * * Fields can be accessed through AVOptions, the name string used, matches the * C structure field name for fields accessible through AVOptions. The AVClass @@ -231,9 +248,18 @@ typedef struct AVFrame { uint8_t **extended_data; /** - * width and height of the video frame + * @name Video dimensions + * Video frames only. The coded dimensions (in pixels) of the video frame, + * i.e. the size of the rectangle that contains some well-defined values. + * + * @note The part of the frame intended for display/presentation is further + * restricted by the @ref cropping "Cropping rectangle". + * @{ */ int width, height; + /** + * @} + */ /** * number of audio samples (per channel) described by this frame @@ -414,8 +440,6 @@ typedef struct AVFrame { /** * MPEG vs JPEG YUV range. - * It must be accessed using av_frame_get_color_range() and - * av_frame_set_color_range(). * - encoding: Set by user * - decoding: Set by libavcodec */ @@ -427,8 +451,6 @@ typedef struct AVFrame { /** * YUV colorspace type. - * It must be accessed using av_frame_get_colorspace() and - * av_frame_set_colorspace(). * - encoding: Set by user * - decoding: Set by libavcodec */ @@ -438,8 +460,6 @@ typedef struct AVFrame { /** * frame timestamp estimated using various heuristics, in stream time base - * Code outside libavutil should access this field using: - * av_frame_get_best_effort_timestamp(frame) * - encoding: unused * - decoding: set by libavcodec, read by user. */ @@ -447,8 +467,6 @@ typedef struct AVFrame { /** * reordered pos from the last AVPacket that has been input into the decoder - * Code outside libavutil should access this field using: - * av_frame_get_pkt_pos(frame) * - encoding: unused * - decoding: Read by user. */ @@ -457,8 +475,6 @@ typedef struct AVFrame { /** * duration of the corresponding packet, expressed in * AVStream->time_base units, 0 if unknown. - * Code outside libavutil should access this field using: - * av_frame_get_pkt_duration(frame) * - encoding: unused * - decoding: Read by user. */ @@ -466,8 +482,6 @@ typedef struct AVFrame { /** * metadata. - * Code outside libavutil should access this field using: - * av_frame_get_metadata(frame) * - encoding: Set by user. * - decoding: Set by libavcodec. */ @@ -477,8 +491,6 @@ typedef struct AVFrame { * decode error flags of the frame, set to a combination of * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there * were errors during the decoding. - * Code outside libavutil should access this field using: - * av_frame_get_decode_error_flags(frame) * - encoding: unused * - decoding: set by libavcodec, read by user. */ @@ -488,8 +500,6 @@ typedef struct AVFrame { /** * number of audio channels, only used for audio. - * Code outside libavutil should access this field using: - * av_frame_get_channels(frame) * - encoding: unused * - decoding: Read by user. */ @@ -497,8 +507,7 @@ typedef struct AVFrame { /** * size of the corresponding packet containing the compressed - * frame. It must be accessed using av_frame_get_pkt_size() and - * av_frame_set_pkt_size(). + * frame. * It is set to a negative value if unknown. * - encoding: unused * - decoding: set by libavcodec, read by user. @@ -508,13 +517,11 @@ typedef struct AVFrame { #if FF_API_FRAME_QP /** * QP table - * Not to be accessed directly from outside libavutil */ attribute_deprecated int8_t *qscale_table; /** * QP store stride - * Not to be accessed directly from outside libavutil */ attribute_deprecated int qstride; @@ -522,9 +529,6 @@ typedef struct AVFrame { attribute_deprecated int qscale_type; - /** - * Not to be accessed directly from outside libavutil - */ AVBufferRef *qp_table_buf; #endif /** @@ -532,12 +536,38 @@ typedef struct AVFrame { * AVHWFramesContext describing the frame. */ AVBufferRef *hw_frames_ctx; + + /** + * AVBufferRef for free use by the API user. FFmpeg will never check the + * contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when + * the frame is unreferenced. av_frame_copy_props() calls create a new + * reference with av_buffer_ref() for the target frame's opaque_ref field. + * + * This is unrelated to the opaque field, although it serves a similar + * purpose. + */ + AVBufferRef *opaque_ref; + + /** + * @anchor cropping + * @name Cropping + * Video frames only. The number of pixels to discard from the the + * top/bottom/left/right border of the frame to obtain the sub-rectangle of + * the frame intended for presentation. + * @{ + */ + size_t crop_top; + size_t crop_bottom; + size_t crop_left; + size_t crop_right; + /** + * @} + */ } AVFrame; /** - * Accessors for some AVFrame fields. - * The position of these field in the structure is not part of the ABI, - * they should not be accessed directly outside libavutil. + * Accessors for some AVFrame fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. */ int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); @@ -651,7 +681,9 @@ void av_frame_move_ref(AVFrame *dst, AVFrame *src); * cases. * * @param frame frame in which to store the new buffers. - * @param align required buffer size alignment + * @param align Required buffer size alignment. If equal to 0, alignment will be + * chosen automatically for the current CPU. It is highly + * recommended to pass 0 here unless you know what you are doing. * * @return 0 on success, a negative AVERROR on error. */ @@ -743,6 +775,40 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, */ void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + +/** + * Flags for frame cropping. + */ +enum { + /** + * Apply the maximum possible cropping, even if it requires setting the + * AVFrame.data[] entries to unaligned pointers. Passing unaligned data + * to FFmpeg API is generally not allowed, and causes undefined behavior + * (such as crashes). You can pass unaligned data only to FFmpeg APIs that + * are explicitly documented to accept it. Use this flag only if you + * absolutely know what you are doing. + */ + AV_FRAME_CROP_UNALIGNED = 1 << 0, +}; + +/** + * Crop the given video AVFrame according to its crop_left/crop_top/crop_right/ + * crop_bottom fields. If cropping is successful, the function will adjust the + * data pointers and the width/height fields, and set the crop fields to 0. + * + * In all cases, the cropping boundaries will be rounded to the inherent + * alignment of the pixel format. In some cases, such as for opaque hwaccel + * formats, the left/top cropping is ignored. The crop fields are set to 0 even + * if the cropping was rounded or ignored. + * + * @param frame the frame which should be cropped + * @param flags Some combination of AV_FRAME_CROP_* flags, or 0. + * + * @return >= 0 on success, a negative AVERROR on error. If the cropping fields + * were invalid, AVERROR(ERANGE) is returned, and nothing is changed. + */ +int av_frame_apply_cropping(AVFrame *frame, int flags); + /** * @return a string identifying the side data type */ diff --git a/media/ffvpx/libavutil/hwcontext.h b/media/ffvpx/libavutil/hwcontext.h index 5e2af092a4..03334e20e0 100644 --- a/media/ffvpx/libavutil/hwcontext.h +++ b/media/ffvpx/libavutil/hwcontext.h @@ -30,6 +30,10 @@ enum AVHWDeviceType { 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, }; typedef struct AVHWDeviceInternal AVHWDeviceInternal; @@ -223,10 +227,36 @@ typedef struct AVHWFramesContext { } AVHWFramesContext; /** - * Allocate an AVHWDeviceContext for a given pixel format. + * Look up an AVHWDeviceType by name. * - * @param format a hwaccel pixel format (AV_PIX_FMT_FLAG_HWACCEL must be set - * on the corresponding format descriptor) + * @param name String name of the device type (case-insensitive). + * @return The type from enum AVHWDeviceType, or AV_HWDEVICE_TYPE_NONE if + * not found. + */ +enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name); + +/** Get the string name of an AVHWDeviceType. + * + * @param type Type from enum AVHWDeviceType. + * @return Pointer to a static string containing the name, or NULL if the type + * is not valid. + */ +const char *av_hwdevice_get_type_name(enum AVHWDeviceType type); + +/** + * Iterate over supported device types. + * + * @param type AV_HWDEVICE_TYPE_NONE initially, then the previous type + * returned by this function in subsequent iterations. + * @return The next usable device type from enum AVHWDeviceType, or + * AV_HWDEVICE_TYPE_NONE if there are no more. + */ +enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev); + +/** + * Allocate an AVHWDeviceContext for a given hardware type. + * + * @param type the type of the hardware device to allocate. * @return a reference to the newly created AVHWDeviceContext on success or NULL * on failure. */ @@ -271,6 +301,32 @@ int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags); /** + * Create a new device of the specified type from an existing device. + * + * If the source device is a device of the target type or was originally + * derived from such a device (possibly through one or more intermediate + * devices of other types), then this will return a reference to the + * existing device of the same type as is requested. + * + * Otherwise, it will attempt to derive a new device from the given source + * device. If direct derivation to the new type is not implemented, it will + * attempt the same derivation from each ancestor of the source device in + * turn looking for an implemented derivation method. + * + * @param dst_ctx On success, a reference to the newly-created + * AVHWDeviceContext. + * @param type The type of the new device to create. + * @param src_ctx A reference to an existing AVHWDeviceContext which will be + * used to create the new device. + * @param flags Currently unused; should be set to zero. + * @return Zero on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ctx, + enum AVHWDeviceType type, + AVBufferRef *src_ctx, int flags); + + +/** * Allocate an AVHWFramesContext tied to a given device context. * * @param device_ctx a reference to a AVHWDeviceContext. This function will make @@ -318,6 +374,14 @@ int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags); * If dst->format is set, then this format will be used, otherwise (when * dst->format is AV_PIX_FMT_NONE) the first acceptable format will be chosen. * + * The two frames must have matching allocated dimensions (i.e. equal to + * AVHWFramesContext.width/height), since not all device types support + * transferring a sub-rectangle of the whole surface. The display dimensions + * (i.e. AVFrame.width/height) may be smaller than the allocated dimensions, but + * also have to be equal for both frames. When the display dimensions are + * smaller than the allocated dimensions, the content of the padding in the + * destination frame is unspecified. + * * @param dst the destination frame. dst is not touched on failure. * @param src the source frame. * @param flags currently unused, should be set to zero @@ -410,7 +474,7 @@ void *av_hwdevice_hwconfig_alloc(AVBufferRef *device_ctx); * configuration is provided, returns the maximum possible capabilities * of the device. * - * @param device_ctx a reference to the associated AVHWDeviceContext. + * @param ref a reference to the associated AVHWDeviceContext. * @param hwconfig a filled HW-specific configuration structure, or NULL * to return the maximum possible capabilities of the device. * @return AVHWFramesConstraints structure describing the constraints @@ -426,4 +490,93 @@ AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, */ void av_hwframe_constraints_free(AVHWFramesConstraints **constraints); + +/** + * Flags to apply to frame mappings. + */ +enum { + /** + * The mapping must be readable. + */ + AV_HWFRAME_MAP_READ = 1 << 0, + /** + * The mapping must be writeable. + */ + AV_HWFRAME_MAP_WRITE = 1 << 1, + /** + * The mapped frame will be overwritten completely in subsequent + * operations, so the current frame data need not be loaded. Any values + * which are not overwritten are unspecified. + */ + AV_HWFRAME_MAP_OVERWRITE = 1 << 2, + /** + * The mapping must be direct. That is, there must not be any copying in + * the map or unmap steps. Note that performance of direct mappings may + * be much lower than normal memory. + */ + AV_HWFRAME_MAP_DIRECT = 1 << 3, +}; + +/** + * Map a hardware frame. + * + * This has a number of different possible effects, depending on the format + * and origin of the src and dst frames. On input, src should be a usable + * frame with valid buffers and dst should be blank (typically as just created + * by av_frame_alloc()). src should have an associated hwframe context, and + * dst may optionally have a format and associated hwframe context. + * + * If src was created by mapping a frame from the hwframe context of dst, + * then this function undoes the mapping - dst is replaced by a reference to + * the frame that src was originally mapped from. + * + * If both src and dst have an associated hwframe context, then this function + * attempts to map the src frame from its hardware context to that of dst and + * then fill dst with appropriate data to be usable there. This will only be + * possible if the hwframe contexts and associated devices are compatible - + * given compatible devices, av_hwframe_ctx_create_derived() can be used to + * create a hwframe context for dst in which mapping should be possible. + * + * If src has a hwframe context but dst does not, then the src frame is + * mapped to normal memory and should thereafter be usable as a normal frame. + * If the format is set on dst, then the mapping will attempt to create dst + * with that format and fail if it is not possible. If format is unset (is + * AV_PIX_FMT_NONE) then dst will be mapped with whatever the most appropriate + * format to use is (probably the sw_format of the src hwframe context). + * + * A return value of AVERROR(ENOSYS) indicates that the mapping is not + * possible with the given arguments and hwframe setup, while other return + * values indicate that it failed somehow. + * + * @param dst Destination frame, to contain the mapping. + * @param src Source frame, to be mapped. + * @param flags Some combination of AV_HWFRAME_MAP_* flags. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags); + + +/** + * Create and initialise an AVHWFramesContext as a mapping of another existing + * AVHWFramesContext on a different device. + * + * av_hwframe_ctx_init() should not be called after this. + * + * @param derived_frame_ctx On success, a reference to the newly created + * AVHWFramesContext. + * @param derived_device_ctx A reference to the device to create the new + * AVHWFramesContext on. + * @param source_frame_ctx A reference to an existing AVHWFramesContext + * which will be mapped to the derived context. + * @param flags Some combination of AV_HWFRAME_MAP_* flags, defining the + * mapping parameters to apply to frames which are allocated + * in the derived device. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, + enum AVPixelFormat format, + AVBufferRef *derived_device_ctx, + AVBufferRef *source_frame_ctx, + int flags); + #endif /* AVUTIL_HWCONTEXT_H */ diff --git a/media/ffvpx/libavutil/imgutils.c b/media/ffvpx/libavutil/imgutils.c index 37808e53d0..5005178804 100644 --- a/media/ffvpx/libavutil/imgutils.c +++ b/media/ffvpx/libavutil/imgutils.c @@ -24,6 +24,7 @@ #include "avassert.h" #include "common.h" #include "imgutils.h" +#include "imgutils_internal.h" #include "internal.h" #include "intreadwrite.h" #include "log.h" @@ -248,19 +249,38 @@ static const AVClass imgutils_class = { .parent_log_context_offset = offsetof(ImgUtils, log_ctx), }; -int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx) { ImgUtils imgutils = { .class = &imgutils_class, .log_offset = log_offset, .log_ctx = log_ctx, }; + int64_t stride = av_image_get_linesize(pix_fmt, w, 0); + if (stride <= 0) + stride = 8LL*w; + stride += 128*8; - if ((int)w>0 && (int)h>0 && (w+128)*(uint64_t)(h+128) < INT_MAX/8) - return 0; + if ((int)w<=0 || (int)h<=0 || stride >= INT_MAX || stride*(uint64_t)(h+128) >= INT_MAX) { + av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h); + return AVERROR(EINVAL); + } - av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h); - return AVERROR(EINVAL); + if (max_pixels < INT64_MAX) { + if (w*(int64_t)h > max_pixels) { + av_log(&imgutils, AV_LOG_ERROR, + "Picture size %ux%u exceeds specified max pixel count %"PRId64", see the documentation if you wish to increase it\n", + w, h, max_pixels); + return AVERROR(EINVAL); + } + } + + return 0; +} + +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +{ + return av_image_check_size2(w, h, INT64_MAX, AV_PIX_FMT_NONE, log_offset, log_ctx); } int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar) @@ -284,9 +304,9 @@ int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar) return AVERROR(EINVAL); } -void av_image_copy_plane(uint8_t *dst, int dst_linesize, - const uint8_t *src, int src_linesize, - int bytewidth, int height) +static void image_copy_plane(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) { if (!dst || !src) return; @@ -299,9 +319,33 @@ void av_image_copy_plane(uint8_t *dst, int dst_linesize, } } -void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], - const uint8_t *src_data[4], const int src_linesizes[4], - enum AVPixelFormat pix_fmt, int width, int height) +static void image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + int ret = -1; + +#if ARCH_X86 + ret = ff_image_copy_plane_uc_from_x86(dst, dst_linesize, src, src_linesize, + bytewidth, height); +#endif + + if (ret < 0) + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height) +{ + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +static void image_copy(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height, + void (*copy_plane)(uint8_t *, ptrdiff_t, const uint8_t *, + ptrdiff_t, ptrdiff_t, int)) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); @@ -310,9 +354,9 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { - av_image_copy_plane(dst_data[0], dst_linesizes[0], - src_data[0], src_linesizes[0], - width, height); + copy_plane(dst_data[0], dst_linesizes[0], + src_data[0], src_linesizes[0], + width, height); /* copy the palette */ memcpy(dst_data[1], src_data[1], 4*256); } else { @@ -323,7 +367,7 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], for (i = 0; i < planes_nb; i++) { int h = height; - int bwidth = av_image_get_linesize(pix_fmt, width, i); + ptrdiff_t bwidth = av_image_get_linesize(pix_fmt, width, i); if (bwidth < 0) { av_log(NULL, AV_LOG_ERROR, "av_image_get_linesize failed\n"); return; @@ -331,13 +375,37 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], if (i == 1 || i == 2) { h = AV_CEIL_RSHIFT(height, desc->log2_chroma_h); } - av_image_copy_plane(dst_data[i], dst_linesizes[i], - src_data[i], src_linesizes[i], - bwidth, h); + copy_plane(dst_data[i], dst_linesizes[i], + src_data[i], src_linesizes[i], + bwidth, h); } } } +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + ptrdiff_t dst_linesizes1[4], src_linesizes1[4]; + int i; + + for (i = 0; i < 4; i++) { + dst_linesizes1[i] = dst_linesizes[i]; + src_linesizes1[i] = src_linesizes[i]; + } + + image_copy(dst_data, dst_linesizes1, src_data, src_linesizes1, pix_fmt, + width, height, image_copy_plane); +} + +void av_image_copy_uc_from(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + image_copy(dst_data, dst_linesizes, src_data, src_linesizes, pix_fmt, + width, height, image_copy_plane_uc_from); +} + int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align) @@ -423,3 +491,170 @@ int av_image_copy_to_buffer(uint8_t *dst, int dst_size, return size; } + +// Fill dst[0..dst_size] with the bytes in clear[0..clear_size]. The clear +// bytes are repeated until dst_size is reached. If dst_size is unaligned (i.e. +// dst_size%clear_size!=0), the remaining data will be filled with the beginning +// of the clear data only. +static void memset_bytes(uint8_t *dst, size_t dst_size, uint8_t *clear, + size_t clear_size) +{ + size_t pos = 0; + int same = 1; + int i; + + if (!clear_size) + return; + + // Reduce to memset() if possible. + for (i = 0; i < clear_size; i++) { + if (clear[i] != clear[0]) { + same = 0; + break; + } + } + if (same) + clear_size = 1; + + if (clear_size == 1) { + memset(dst, clear[0], dst_size); + dst_size = 0; + } else if (clear_size == 2) { + uint16_t val = AV_RN16(clear); + for (; dst_size >= 2; dst_size -= 2) { + AV_WN16(dst, val); + dst += 2; + } + } else if (clear_size == 4) { + uint32_t val = AV_RN32(clear); + for (; dst_size >= 4; dst_size -= 4) { + AV_WN32(dst, val); + dst += 4; + } + } else if (clear_size == 8) { + uint32_t val = AV_RN64(clear); + for (; dst_size >= 8; dst_size -= 8) { + AV_WN64(dst, val); + dst += 8; + } + } + + for (; dst_size; dst_size--) + *dst++ = clear[pos++ % clear_size]; +} + +// Maximum size in bytes of a plane element (usually a pixel, or multiple pixels +// if it's a subsampled packed format). +#define MAX_BLOCK_SIZE 32 + +int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int nb_planes = av_pix_fmt_count_planes(pix_fmt); + // A pixel or a group of pixels on each plane, with a value that represents black. + // Consider e.g. AV_PIX_FMT_UYVY422 for non-trivial cases. + uint8_t clear_block[4][MAX_BLOCK_SIZE] = {{0}}; // clear padding with 0 + int clear_block_size[4] = {0}; + ptrdiff_t plane_line_bytes[4] = {0}; + int rgb, limited; + int plane, c; + + if (!desc || nb_planes < 1 || nb_planes > 4 || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + rgb = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); + limited = !rgb && range != AVCOL_RANGE_JPEG; + + if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) { + ptrdiff_t bytewidth = av_image_get_linesize(pix_fmt, width, 0); + uint8_t *data; + int mono = pix_fmt == AV_PIX_FMT_MONOWHITE || pix_fmt == AV_PIX_FMT_MONOBLACK; + int fill = pix_fmt == AV_PIX_FMT_MONOWHITE ? 0xFF : 0; + if (nb_planes != 1 || !(rgb || mono) || bytewidth < 1) + return AVERROR(EINVAL); + + if (!dst_data) + return 0; + + data = dst_data[0]; + + // (Bitstream + alpha will be handled incorrectly - it'll remain transparent.) + for (;height > 0; height--) { + memset(data, fill, bytewidth); + data += dst_linesize[0]; + } + return 0; + } + + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + + // We try to operate on entire non-subsampled pixel groups (for + // AV_PIX_FMT_UYVY422 this would mean two consecutive pixels). + clear_block_size[comp.plane] = FFMAX(clear_block_size[comp.plane], comp.step); + + if (clear_block_size[comp.plane] > MAX_BLOCK_SIZE) + return AVERROR(EINVAL); + } + + // Create a byte array for clearing 1 pixel (sometimes several pixels). + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + // (Multiple pixels happen e.g. with AV_PIX_FMT_UYVY422.) + int w = clear_block_size[comp.plane] / comp.step; + uint8_t *c_data[4]; + const int c_linesize[4] = {0}; + uint16_t src_array[MAX_BLOCK_SIZE]; + uint16_t src = 0; + int x; + + if (comp.depth > 16) + return AVERROR(EINVAL); + if (!rgb && comp.depth < 8) + return AVERROR(EINVAL); + if (w < 1) + return AVERROR(EINVAL); + + if (c == 0 && limited) { + src = 16 << (comp.depth - 8); + } else if ((c == 1 || c == 2) && !rgb) { + src = 128 << (comp.depth - 8); + } else if (c == 3) { + // (Assume even limited YUV uses full range alpha.) + src = (1 << comp.depth) - 1; + } + + for (x = 0; x < w; x++) + src_array[x] = src; + + for (x = 0; x < 4; x++) + c_data[x] = &clear_block[x][0]; + + av_write_image_line(src_array, c_data, c_linesize, desc, 0, 0, c, w); + } + + for (plane = 0; plane < nb_planes; plane++) { + plane_line_bytes[plane] = av_image_get_linesize(pix_fmt, width, plane); + if (plane_line_bytes[plane] < 0) + return AVERROR(EINVAL); + } + + if (!dst_data) + return 0; + + for (plane = 0; plane < nb_planes; plane++) { + size_t bytewidth = plane_line_bytes[plane]; + uint8_t *data = dst_data[plane]; + int chroma_div = plane == 1 || plane == 2 ? desc->log2_chroma_h : 0; + int plane_h = ((height + ( 1 << chroma_div) - 1)) >> chroma_div; + + for (; plane_h > 0; plane_h--) { + memset_bytes(data, bytewidth, &clear_block[plane][0], clear_block_size[plane]); + data += dst_linesize[plane]; + } + } + + return 0; +} diff --git a/media/ffvpx/libavutil/imgutils.h b/media/ffvpx/libavutil/imgutils.h index 23282a38fa..5b790ecf0a 100644 --- a/media/ffvpx/libavutil/imgutils.h +++ b/media/ffvpx/libavutil/imgutils.h @@ -121,6 +121,24 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height); /** + * Copy image data located in uncacheable (e.g. GPU mapped) memory. Where + * available, this function will use special functionality for reading from such + * memory, which may result in greatly improved performance compared to plain + * av_image_copy(). + * + * The data pointers and the linesizes must be aligned to the maximum required + * by the CPU architecture. + * + * @note The linesize parameters have the type ptrdiff_t here, while they are + * int for av_image_copy(). + * @note On x86, the linesizes currently need to be aligned to the cacheline + * size (i.e. 64) to get improved performance. + */ +void av_image_copy_uc_from(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** * Setup the data pointers and linesizes based on the specified image * parameters and the provided array. * @@ -137,7 +155,7 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], * one call, use av_image_alloc(). * * @param dst_data data pointers to be filled in - * @param dst_linesizes linesizes for the image in dst_data to be filled in + * @param dst_linesize linesizes for the image in dst_data to be filled in * @param src buffer which will contain or contains the actual image data, can be NULL * @param pix_fmt the pixel format of the image * @param width the width of the image in pixels @@ -154,7 +172,11 @@ int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], * Return the size in bytes of the amount of data required to store an * image with the given parameters. * - * @param[in] align the assumed linesize alignment + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the assumed linesize alignment + * @return the buffer size in bytes, a negative error code in case of failure */ int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); @@ -167,7 +189,7 @@ int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, * @param dst a buffer into which picture data will be copied * @param dst_size the size in bytes of dst * @param src_data pointers containing the source image data - * @param src_linesizes linesizes for the image in src_data + * @param src_linesize linesizes for the image in src_data * @param pix_fmt the pixel format of the source image * @param width the width of the source image in pixels * @param height the height of the source image in pixels @@ -192,6 +214,21 @@ int av_image_copy_to_buffer(uint8_t *dst, int dst_size, int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); /** + * Check if the given dimension of an image is valid, meaning that all + * bytes of a plane of an image with the specified pix_fmt can be addressed + * with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param max_pixels the maximum number of pixels the user wants to accept + * @param pix_fmt the pixel format, can be AV_PIX_FMT_NONE if unknown. + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx); + +/** * Check if the given sample aspect ratio of an image is valid. * * It is considered invalid if the denominator is 0 or if applying the ratio @@ -206,6 +243,33 @@ int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *lo int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); /** + * Overwrite the image data with black. This is suitable for filling a + * sub-rectangle of an image, meaning the padding between the right most pixel + * and the left most pixel on the next line will not be overwritten. For some + * formats, the image size might be rounded up due to inherent alignment. + * + * If the pixel format has alpha, the alpha is cleared to opaque. + * + * This can return an error if the pixel format is not supported. Normally, all + * non-hwaccel pixel formats should be supported. + * + * Passing NULL for dst_data is allowed. Then the function returns whether the + * operation would have succeeded. (It can return an error if the pix_fmt is + * not supported.) + * + * @param dst_data data pointers to destination image + * @param dst_linesize linesizes for the destination image + * @param pix_fmt the pixel format of the image + * @param range the color range of the image (important for colorspaces such as YUV) + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @return 0 if the image data was cleared, a negative AVERROR code otherwise + */ +int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height); + +/** * @} */ diff --git a/media/ffvpx/libavutil/imgutils_internal.h b/media/ffvpx/libavutil/imgutils_internal.h new file mode 100644 index 0000000000..d515858413 --- /dev/null +++ b/media/ffvpx/libavutil/imgutils_internal.h @@ -0,0 +1,30 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_INTERNAL_H +#define AVUTIL_IMGUTILS_INTERNAL_H + +#include <stddef.h> +#include <stdint.h> + +int ff_image_copy_plane_uc_from_x86(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height); + + +#endif /* AVUTIL_IMGUTILS_INTERNAL_H */ diff --git a/media/ffvpx/libavutil/internal.h b/media/ffvpx/libavutil/internal.h index e995af97e4..a2d73e3cc6 100644 --- a/media/ffvpx/libavutil/internal.h +++ b/media/ffvpx/libavutil/internal.h @@ -30,6 +30,9 @@ # define NDEBUG #endif +// This can be enabled to allow detection of additional integer overflows with ubsan +//#define CHECKED + #include <limits.h> #include <stdint.h> #include <stddef.h> @@ -258,6 +261,16 @@ void avpriv_request_sample(void *avc, # define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) #endif +// For debuging we use signed operations so overflows can be detected (by ubsan) +// For production we use unsigned so there are no undefined operations +#ifdef CHECKED +#define SUINT int +#define SUINT32 int32_t +#else +#define SUINT unsigned +#define SUINT32 uint32_t +#endif + /** * Clip and convert a double value into the long long amin-amax range. * This function is needed because conversion of floating point to integers when @@ -340,6 +353,4 @@ void ff_check_pixfmt_descriptors(void); */ int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp); -extern const uint8_t ff_reverse[256]; - #endif /* AVUTIL_INTERNAL_H */ diff --git a/media/ffvpx/libavutil/intreadwrite.h b/media/ffvpx/libavutil/intreadwrite.h index 51fbe30a23..d54d4b91d6 100644 --- a/media/ffvpx/libavutil/intreadwrite.h +++ b/media/ffvpx/libavutil/intreadwrite.h @@ -229,6 +229,11 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; # 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))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + #elif AV_HAVE_FAST_UNALIGNED # define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) @@ -242,8 +247,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; ((const uint8_t*)(x))[1]) #endif #ifndef AV_WB16 -# define AV_WB16(p, darg) do { \ - unsigned d = (darg); \ +# define AV_WB16(p, val) do { \ + uint16_t d = (val); \ ((uint8_t*)(p))[1] = (d); \ ((uint8_t*)(p))[0] = (d)>>8; \ } while(0) @@ -255,8 +260,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; ((const uint8_t*)(x))[0]) #endif #ifndef AV_WL16 -# define AV_WL16(p, darg) do { \ - unsigned d = (darg); \ +# define AV_WL16(p, val) do { \ + uint16_t d = (val); \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ } while(0) @@ -270,8 +275,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; ((const uint8_t*)(x))[3]) #endif #ifndef AV_WB32 -# define AV_WB32(p, darg) do { \ - unsigned d = (darg); \ +# define AV_WB32(p, val) do { \ + uint32_t d = (val); \ ((uint8_t*)(p))[3] = (d); \ ((uint8_t*)(p))[2] = (d)>>8; \ ((uint8_t*)(p))[1] = (d)>>16; \ @@ -287,8 +292,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; ((const uint8_t*)(x))[0]) #endif #ifndef AV_WL32 -# define AV_WL32(p, darg) do { \ - unsigned d = (darg); \ +# define AV_WL32(p, val) do { \ + uint32_t d = (val); \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ ((uint8_t*)(p))[2] = (d)>>16; \ @@ -308,8 +313,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; (uint64_t)((const uint8_t*)(x))[7]) #endif #ifndef AV_WB64 -# define AV_WB64(p, darg) do { \ - uint64_t d = (darg); \ +# define AV_WB64(p, val) do { \ + uint64_t d = (val); \ ((uint8_t*)(p))[7] = (d); \ ((uint8_t*)(p))[6] = (d)>>8; \ ((uint8_t*)(p))[5] = (d)>>16; \ @@ -333,8 +338,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; (uint64_t)((const uint8_t*)(x))[0]) #endif #ifndef AV_WL64 -# define AV_WL64(p, darg) do { \ - uint64_t d = (darg); \ +# define AV_WL64(p, val) do { \ + uint64_t d = (val); \ ((uint8_t*)(p))[0] = (d); \ ((uint8_t*)(p))[1] = (d)>>8; \ ((uint8_t*)(p))[2] = (d)>>16; \ diff --git a/media/ffvpx/libavutil/log.c b/media/ffvpx/libavutil/log.c index 44c11cb091..be806202ff 100644 --- a/media/ffvpx/libavutil/log.c +++ b/media/ffvpx/libavutil/log.c @@ -168,19 +168,19 @@ static void colored_fputs(int level, int tint, const char *str) #else if (local_use_color == 1) { fprintf(stderr, - "\033[%d;3%dm%s\033[0m", + "\033[%"PRIu32";3%"PRIu32"m%s\033[0m", (color[level] >> 4) & 15, color[level] & 15, str); } else if (tint && use_color == 256) { fprintf(stderr, - "\033[48;5;%dm\033[38;5;%dm%s\033[0m", + "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m", (color[level] >> 16) & 0xff, tint, str); } else if (local_use_color == 256) { fprintf(stderr, - "\033[48;5;%dm\033[38;5;%dm%s\033[0m", + "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m", (color[level] >> 16) & 0xff, (color[level] >> 8) & 0xff, str); diff --git a/media/ffvpx/libavutil/mathematics.c b/media/ffvpx/libavutil/mathematics.c index 20ff37f5e9..1bf044cdf1 100644 --- a/media/ffvpx/libavutil/mathematics.c +++ b/media/ffvpx/libavutil/mathematics.c @@ -115,15 +115,15 @@ int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) if (t1 > INT64_MAX) return INT64_MIN; return t1; - } #else + /* reference code doing (a*b + r) / c, requires libavutil/integer.h */ AVInteger ai; ai = av_mul_i(av_int2i(a), av_int2i(b)); ai = av_add_i(ai, av_int2i(r)); return av_i2int(av_div_i(ai, av_int2i(c))); - } #endif + } } int64_t av_rescale(int64_t a, int64_t b, int64_t c) diff --git a/media/ffvpx/libavutil/mem.c b/media/ffvpx/libavutil/mem.c index 1a8fc21e98..36740f1154 100644 --- a/media/ffvpx/libavutil/mem.c +++ b/media/ffvpx/libavutil/mem.c @@ -77,22 +77,12 @@ void av_max_alloc(size_t max){ void *av_malloc(size_t size) { void *ptr = NULL; -#if CONFIG_MEMALIGN_HACK - long diff; -#endif /* let's disallow possibly ambiguous cases */ if (size > (max_alloc_size - 32)) return NULL; -#if CONFIG_MEMALIGN_HACK - ptr = malloc(size + ALIGN); - if (!ptr) - return ptr; - diff = ((~(long)ptr)&(ALIGN - 1)) + 1; - ptr = (char *)ptr + diff; - ((char *)ptr)[-1] = diff; -#elif HAVE_POSIX_MEMALIGN +#if HAVE_POSIX_MEMALIGN if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation if (posix_memalign(&ptr, ALIGN, size)) ptr = NULL; @@ -144,25 +134,11 @@ void *av_malloc(size_t size) void *av_realloc(void *ptr, size_t size) { -#if CONFIG_MEMALIGN_HACK - int diff; -#endif - /* let's disallow possibly ambiguous cases */ if (size > (max_alloc_size - 32)) return NULL; -#if CONFIG_MEMALIGN_HACK - //FIXME this isn't aligned correctly, though it probably isn't needed - if (!ptr) - return av_malloc(size); - diff = ((char *)ptr)[-1]; - av_assert0(diff>0 && diff<=ALIGN); - ptr = realloc((char *)ptr - diff, size + diff); - if (ptr) - ptr = (char *)ptr + diff; - return ptr; -#elif HAVE_ALIGNED_MALLOC +#if HAVE_ALIGNED_MALLOC return _aligned_realloc(ptr, size + !size, ALIGN); #else return realloc(ptr, size + !size); @@ -227,13 +203,7 @@ int av_reallocp_array(void *ptr, size_t nmemb, size_t size) void av_free(void *ptr) { -#if CONFIG_MEMALIGN_HACK - if (ptr) { - int v= ((char *)ptr)[-1]; - av_assert0(v>0 && v<=ALIGN); - free((char *)ptr - v); - } -#elif HAVE_ALIGNED_MALLOC +#if HAVE_ALIGNED_MALLOC _aligned_free(ptr); #else free(ptr); diff --git a/media/ffvpx/libavutil/mem.h b/media/ffvpx/libavutil/mem.h index f9d8884788..527cd03191 100644 --- a/media/ffvpx/libavutil/mem.h +++ b/media/ffvpx/libavutil/mem.h @@ -97,7 +97,10 @@ #define DECLARE_ASM_CONST(n,t,v) \ AV_PRAGMA(DATA_ALIGN(v,n)) \ static const t __attribute__((aligned(n))) v -#elif defined(__GNUC__) +#elif defined(__DJGPP__) + #define DECLARE_ALIGNED(n,t,v) t __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_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v #elif defined(_MSC_VER) diff --git a/media/ffvpx/libavutil/moz.build b/media/ffvpx/libavutil/moz.build index a1c920f427..84433ad6e6 100644 --- a/media/ffvpx/libavutil/moz.build +++ b/media/ffvpx/libavutil/moz.build @@ -45,6 +45,7 @@ SOURCES += [ 'rational.c', 'reverse.c', 'samplefmt.c', + 'slicethread.c', 'threadmessage.c', 'time.c', 'timecode.c', diff --git a/media/ffvpx/libavutil/opt.c b/media/ffvpx/libavutil/opt.c index cd16bd1d3f..df88663e3f 100644 --- a/media/ffvpx/libavutil/opt.c +++ b/media/ffvpx/libavutil/opt.c @@ -74,6 +74,7 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den case AV_OPT_TYPE_CHANNEL_LAYOUT: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: *intnum = *(int64_t *)dst; return 0; case AV_OPT_TYPE_FLOAT: @@ -96,8 +97,8 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum) { if (o->type != AV_OPT_TYPE_FLAGS && - (o->max * den < num * intnum || o->min * den > num * intnum)) { - num = den ? num * intnum / den : (num * intnum ? INFINITY : NAN); + (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { + num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", num, o->name, o->min, o->max); return AVERROR(ERANGE); @@ -126,9 +127,27 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int break; case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_CHANNEL_LAYOUT: - case AV_OPT_TYPE_INT64: - *(int64_t *)dst = llrint(num / den) * intnum; - break; + case AV_OPT_TYPE_INT64:{ + double d = num / den; + if (intnum == 1 && d == (double)INT64_MAX) { + *(int64_t *)dst = INT64_MAX; + } else + *(int64_t *)dst = llrint(d) * intnum; + break;} + case AV_OPT_TYPE_UINT64:{ + double d = num / den; + // We must special case uint64_t here as llrint() does not support values + // outside the int64_t range and there is no portable function which does + // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double + // while INT64_MAX is not + if (intnum == 1 && d == (double)UINT64_MAX) { + *(uint64_t *)dst = UINT64_MAX; + } else if (d > INT64_MAX + 1ULL) { + *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum; + } else { + *(uint64_t *)dst = llrint(d) * intnum; + } + break;} case AV_OPT_TYPE_FLOAT: *(float *)dst = num * intnum / den; break; @@ -200,6 +219,7 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d } #define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \ + opt->type == AV_OPT_TYPE_UINT64 || \ opt->type == AV_OPT_TYPE_CONST || \ opt->type == AV_OPT_TYPE_FLAGS || \ opt->type == AV_OPT_TYPE_INT) \ @@ -291,8 +311,6 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con if (!i || !*val) return 0; } - - return 0; } static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst) @@ -456,6 +474,7 @@ int av_opt_set(void *obj, const char *name, const char *val, int search_flags) case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_FLOAT: case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_RATIONAL: @@ -756,6 +775,9 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) case AV_OPT_TYPE_INT64: ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t *)dst); break; + case AV_OPT_TYPE_UINT64: + ret = snprintf(buf, sizeof(buf), "%"PRIu64, *(uint64_t *)dst); + break; case AV_OPT_TYPE_FLOAT: ret = snprintf(buf, sizeof(buf), "%f", *(float *)dst); break; @@ -1104,6 +1126,9 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit, case AV_OPT_TYPE_INT64: av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int64>"); break; + case AV_OPT_TYPE_UINT64: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<uint64>"); + break; case AV_OPT_TYPE_DOUBLE: av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<double>"); break; @@ -1164,6 +1189,7 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit, switch (opt->type) { case AV_OPT_TYPE_INT: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_FLOAT: case AV_OPT_TYPE_RATIONAL: @@ -1208,6 +1234,7 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit, break; } case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_INT64: { const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64); if (def_const) @@ -1286,6 +1313,7 @@ void av_opt_set_defaults2(void *s, int mask, int flags) case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_CHANNEL_LAYOUT: case AV_OPT_TYPE_PIXEL_FMT: @@ -1646,6 +1674,7 @@ static int opt_size(enum AVOptionType type) case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_CHANNEL_LAYOUT: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: return sizeof(int64_t); case AV_OPT_TYPE_DOUBLE: return sizeof(double); @@ -1775,6 +1804,7 @@ int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const ch case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_PIXEL_FMT: case AV_OPT_TYPE_SAMPLE_FMT: case AV_OPT_TYPE_FLOAT: @@ -1864,6 +1894,7 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o) case AV_OPT_TYPE_CHANNEL_LAYOUT: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: read_number(o, dst, NULL, NULL, &i64); return o->default_val.i64 == i64; case AV_OPT_TYPE_STRING: diff --git a/media/ffvpx/libavutil/opt.h b/media/ffvpx/libavutil/opt.h index 9430b989e9..0d893795de 100644 --- a/media/ffvpx/libavutil/opt.h +++ b/media/ffvpx/libavutil/opt.h @@ -228,6 +228,7 @@ enum AVOptionType{ AV_OPT_TYPE_RATIONAL, AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length AV_OPT_TYPE_DICT, + AV_OPT_TYPE_UINT64, AV_OPT_TYPE_CONST = 128, AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), diff --git a/media/ffvpx/libavutil/parseutils.c b/media/ffvpx/libavutil/parseutils.c index a2464cfc6e..be4ea1ee15 100644 --- a/media/ffvpx/libavutil/parseutils.c +++ b/media/ffvpx/libavutil/parseutils.c @@ -140,6 +140,11 @@ static const VideoRateAbbr video_rate_abbrs[]= { { "ntsc-film", { 24000, 1001 } }, }; +static const char *months[12] = { + "january", "february", "march", "april", "may", "june", "july", "august", + "september", "october", "november", "december" +}; + int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) { int i; @@ -466,6 +471,21 @@ static int date_get_num(const char **pp, return val; } +static int date_get_month(const char **pp) { + int i = 0; + for (; i < 12; i++) { + if (!av_strncasecmp(*pp, months[i], 3)) { + const char *mo_full = months[i] + 3; + int len = strlen(mo_full); + *pp += 3; + if (len > 0 && !av_strncasecmp(*pp, mo_full, len)) + *pp += len; + return i; + } + } + return -1; +} + char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) { int c, val; @@ -525,6 +545,14 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) if (!p) return NULL; break; + case 'b': + case 'B': + case 'h': + val = date_get_month(&p); + if (val == -1) + return NULL; + dt->tm_mon = val; + break; case '%': if (*p++ != '%') return NULL; diff --git a/media/ffvpx/libavutil/pixdesc.c b/media/ffvpx/libavutil/pixdesc.c index b715fce15d..2cfab89c03 100644 --- a/media/ffvpx/libavutil/pixdesc.c +++ b/media/ffvpx/libavutil/pixdesc.c @@ -560,6 +560,69 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_RGB, }, + [AV_PIX_FMT_GRAY9BE] = { + .name = "gray9be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y9be", + }, + [AV_PIX_FMT_GRAY9LE] = { + .name = "gray9le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + }, + .alias = "y9le", + }, + [AV_PIX_FMT_GRAY10BE] = { + .name = "gray10be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y10be", + }, + [AV_PIX_FMT_GRAY10LE] = { + .name = "gray10le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + }, + .alias = "y10le", + }, + [AV_PIX_FMT_GRAY12BE] = { + .name = "gray12be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y12be", + }, + [AV_PIX_FMT_GRAY12LE] = { + .name = "gray12le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + }, + .alias = "y12le", + }, [AV_PIX_FMT_GRAY16BE] = { .name = "gray16be", .nb_components = 1, @@ -1873,62 +1936,62 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { [AV_PIX_FMT_BAYER_BGGR8] = { .name = "bayer_bggr8", BAYER8_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_BGGR16LE] = { .name = "bayer_bggr16le", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_BGGR16BE] = { .name = "bayer_bggr16be", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_RGGB8] = { .name = "bayer_rggb8", BAYER8_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_RGGB16LE] = { .name = "bayer_rggb16le", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_RGGB16BE] = { .name = "bayer_rggb16be", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_GBRG8] = { .name = "bayer_gbrg8", BAYER8_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_GBRG16LE] = { .name = "bayer_gbrg16le", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_GBRG16BE] = { .name = "bayer_gbrg16be", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_GRBG8] = { .name = "bayer_grbg8", BAYER8_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_GRBG16LE] = { .name = "bayer_grbg16le", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_BAYER_GRBG16BE] = { .name = "bayer_grbg16be", BAYER16_DESC_COMMON - .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, }, [AV_PIX_FMT_NV16] = { .name = "nv16", @@ -2036,6 +2099,30 @@ 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_P016LE] = { + .name = "p016le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ + { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P016BE] = { + .name = "p016be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ + { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, [AV_PIX_FMT_GBRAP12LE] = { .name = "gbrap12le", .nb_components = 4, @@ -2092,18 +2179,80 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, }, + [AV_PIX_FMT_D3D11] = { + .name = "d3d11", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GBRPF32BE] = { + .name = "gbrpf32be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRPF32LE] = { + .name = "gbrpf32le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRAPF32BE] = { + .name = "gbrapf32be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + { 3, 4, 0, 0, 32, 3, 31, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_ALPHA | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRAPF32LE] = { + .name = "gbrapf32le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + { 3, 4, 0, 0, 32, 3, 31, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_DRM_PRIME] = { + .name = "drm_prime", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, }; #if FF_API_PLUS1_MINUS1 FF_ENABLE_DEPRECATION_WARNINGS #endif -static const char *color_range_names[] = { +static const char * const color_range_names[] = { [AVCOL_RANGE_UNSPECIFIED] = "unknown", [AVCOL_RANGE_MPEG] = "tv", [AVCOL_RANGE_JPEG] = "pc", }; -static const char *color_primaries_names[AVCOL_PRI_NB] = { +static const char * const color_primaries_names[AVCOL_PRI_NB] = { [AVCOL_PRI_RESERVED0] = "reserved", [AVCOL_PRI_BT709] = "bt709", [AVCOL_PRI_UNSPECIFIED] = "unknown", @@ -2114,12 +2263,13 @@ static const char *color_primaries_names[AVCOL_PRI_NB] = { [AVCOL_PRI_SMPTE240M] = "smpte240m", [AVCOL_PRI_FILM] = "film", [AVCOL_PRI_BT2020] = "bt2020", - [AVCOL_PRI_SMPTEST428_1] = "smpte428-1", + [AVCOL_PRI_SMPTE428] = "smpte428", [AVCOL_PRI_SMPTE431] = "smpte431", [AVCOL_PRI_SMPTE432] = "smpte432", + [AVCOL_PRI_JEDEC_P22] = "jedec-p22", }; -static const char *color_transfer_names[] = { +static const char * const color_transfer_names[] = { [AVCOL_TRC_RESERVED0] = "reserved", [AVCOL_TRC_BT709] = "bt709", [AVCOL_TRC_UNSPECIFIED] = "unknown", @@ -2135,13 +2285,13 @@ static const char *color_transfer_names[] = { [AVCOL_TRC_BT1361_ECG] = "bt1361e", [AVCOL_TRC_IEC61966_2_1] = "iec61966-2-1", [AVCOL_TRC_BT2020_10] = "bt2020-10", - [AVCOL_TRC_BT2020_12] = "bt2020-20", - [AVCOL_TRC_SMPTEST2084] = "smpte2084", - [AVCOL_TRC_SMPTEST428_1] = "smpte428-1", + [AVCOL_TRC_BT2020_12] = "bt2020-12", + [AVCOL_TRC_SMPTE2084] = "smpte2084", + [AVCOL_TRC_SMPTE428] = "smpte428", [AVCOL_TRC_ARIB_STD_B67] = "arib-std-b67", }; -static const char *color_space_names[] = { +static const char * const color_space_names[] = { [AVCOL_SPC_RGB] = "gbr", [AVCOL_SPC_BT709] = "bt709", [AVCOL_SPC_UNSPECIFIED] = "unknown", @@ -2150,13 +2300,16 @@ static const char *color_space_names[] = { [AVCOL_SPC_BT470BG] = "bt470bg", [AVCOL_SPC_SMPTE170M] = "smpte170m", [AVCOL_SPC_SMPTE240M] = "smpte240m", - [AVCOL_SPC_YCOCG] = "ycgco", + [AVCOL_SPC_YCGCO] = "ycgco", [AVCOL_SPC_BT2020_NCL] = "bt2020nc", [AVCOL_SPC_BT2020_CL] = "bt2020c", [AVCOL_SPC_SMPTE2085] = "smpte2085", + [AVCOL_SPC_CHROMA_DERIVED_NCL] = "chroma-derived-nc", + [AVCOL_SPC_CHROMA_DERIVED_CL] = "chroma-derived-c", + [AVCOL_SPC_ICTCP] = "ictcp", }; -static const char *chroma_location_names[] = { +static const char * const chroma_location_names[] = { [AVCHROMA_LOC_UNSPECIFIED] = "unspecified", [AVCHROMA_LOC_LEFT] = "left", [AVCHROMA_LOC_CENTER] = "center", @@ -2349,7 +2502,7 @@ void ff_check_pixfmt_descriptors(void){ } else { av_assert0(8*c->step >= c->depth); } - if (!strncmp(d->name, "bayer_", 6)) + if (d->flags & AV_PIX_FMT_FLAG_BAYER) continue; av_read_image_line(tmp, (void*)data, linesize, d, 0, 0, j, 2, 0); av_assert0(tmp[0] == 0 && tmp[1] == 0); @@ -2440,8 +2593,16 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt, int ret, loss, i, nb_components; int score = INT_MAX - 1; - if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE) - return ~0; + if (!src_desc || !dst_desc) + return -4; + + if ((src_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) || + (dst_desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { + if (dst_pix_fmt == src_pix_fmt) + return -1; + else + return -2; + } /* compute loss */ *lossp = loss = 0; @@ -2450,9 +2611,9 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt, return INT_MAX; if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0) - return ret; + return -3; if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0) - return ret; + return -3; src_color = get_color_type(src_desc); dst_color = get_color_type(dst_desc); @@ -2554,21 +2715,27 @@ enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, en const AVPixFmtDescriptor *desc2 = av_pix_fmt_desc_get(dst_pix_fmt2); int score1, score2; - loss_mask= loss_ptr?~*loss_ptr:~0; /* use loss mask if provided */ - if(!has_alpha) - loss_mask &= ~FF_LOSS_ALPHA; + if (!desc1) { + dst_pix_fmt = dst_pix_fmt2; + } else if (!desc2) { + dst_pix_fmt = dst_pix_fmt1; + } else { + loss_mask= loss_ptr?~*loss_ptr:~0; /* use loss mask if provided */ + if(!has_alpha) + loss_mask &= ~FF_LOSS_ALPHA; - score1 = get_pix_fmt_score(dst_pix_fmt1, src_pix_fmt, &loss1, loss_mask); - score2 = get_pix_fmt_score(dst_pix_fmt2, src_pix_fmt, &loss2, loss_mask); + score1 = get_pix_fmt_score(dst_pix_fmt1, src_pix_fmt, &loss1, loss_mask); + score2 = get_pix_fmt_score(dst_pix_fmt2, src_pix_fmt, &loss2, loss_mask); - if (score1 == score2) { - if(av_get_padded_bits_per_pixel(desc2) != av_get_padded_bits_per_pixel(desc1)) { - dst_pix_fmt = av_get_padded_bits_per_pixel(desc2) < av_get_padded_bits_per_pixel(desc1) ? dst_pix_fmt2 : dst_pix_fmt1; + if (score1 == score2) { + if(av_get_padded_bits_per_pixel(desc2) != av_get_padded_bits_per_pixel(desc1)) { + dst_pix_fmt = av_get_padded_bits_per_pixel(desc2) < av_get_padded_bits_per_pixel(desc1) ? dst_pix_fmt2 : dst_pix_fmt1; + } else { + dst_pix_fmt = desc2->nb_components < desc1->nb_components ? dst_pix_fmt2 : dst_pix_fmt1; + } } else { - dst_pix_fmt = desc2->nb_components < desc1->nb_components ? dst_pix_fmt2 : dst_pix_fmt1; + dst_pix_fmt = score1 < score2 ? dst_pix_fmt2 : dst_pix_fmt1; } - } else { - dst_pix_fmt = score1 < score2 ? dst_pix_fmt2 : dst_pix_fmt1; } if (loss_ptr) @@ -2582,26 +2749,91 @@ const char *av_color_range_name(enum AVColorRange range) color_range_names[range] : NULL; } +int av_color_range_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_range_names); i++) { + size_t len = strlen(color_range_names[i]); + if (!strncmp(color_range_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + const char *av_color_primaries_name(enum AVColorPrimaries primaries) { return (unsigned) primaries < AVCOL_PRI_NB ? color_primaries_names[primaries] : NULL; } +int av_color_primaries_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_primaries_names); i++) { + size_t len = strlen(color_primaries_names[i]); + if (!strncmp(color_primaries_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer) { return (unsigned) transfer < AVCOL_TRC_NB ? color_transfer_names[transfer] : NULL; } +int av_color_transfer_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_transfer_names); i++) { + size_t len = strlen(color_transfer_names[i]); + if (!strncmp(color_transfer_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + const char *av_color_space_name(enum AVColorSpace space) { return (unsigned) space < AVCOL_SPC_NB ? color_space_names[space] : NULL; } +int av_color_space_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_space_names); i++) { + size_t len = strlen(color_space_names[i]); + if (!strncmp(color_space_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + const char *av_chroma_location_name(enum AVChromaLocation location) { return (unsigned) location < AVCHROMA_LOC_NB ? chroma_location_names[location] : NULL; } + +int av_chroma_location_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(chroma_location_names); i++) { + size_t len = strlen(chroma_location_names[i]); + if (!strncmp(chroma_location_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} diff --git a/media/ffvpx/libavutil/pixdesc.h b/media/ffvpx/libavutil/pixdesc.h index a8ad588913..fc3737c4ad 100644 --- a/media/ffvpx/libavutil/pixdesc.h +++ b/media/ffvpx/libavutil/pixdesc.h @@ -173,6 +173,17 @@ typedef struct AVPixFmtDescriptor { #define AV_PIX_FMT_FLAG_ALPHA (1 << 7) /** + * The pixel format is following a Bayer pattern + */ +#define AV_PIX_FMT_FLAG_BAYER (1 << 8) + +/** + * The pixel format contains IEEE-754 floating point values. Precision (double, + * single, or half) should be determined by the pixel size (64, 32, or 16 bits). + */ +#define AV_PIX_FMT_FLAG_FLOAT (1 << 9) + +/** * Return the number of bits per pixel used by the pixel format * described by pixdesc. Note that this is not the same as the number * of bits per sample. @@ -240,26 +251,51 @@ int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); const char *av_color_range_name(enum AVColorRange range); /** + * @return the AVColorRange value for name or an AVError if not found. + */ +int av_color_range_from_name(const char *name); + +/** * @return the name for provided color primaries or NULL if unknown. */ const char *av_color_primaries_name(enum AVColorPrimaries primaries); /** + * @return the AVColorPrimaries value for name or an AVError if not found. + */ +int av_color_primaries_from_name(const char *name); + +/** * @return the name for provided color transfer or NULL if unknown. */ const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); /** + * @return the AVColorTransferCharacteristic value for name or an AVError if not found. + */ +int av_color_transfer_from_name(const char *name); + +/** * @return the name for provided color space or NULL if unknown. */ const char *av_color_space_name(enum AVColorSpace space); /** + * @return the AVColorSpace value for name or an AVError if not found. + */ +int av_color_space_from_name(const char *name); + +/** * @return the name for provided chroma location or NULL if unknown. */ const char *av_chroma_location_name(enum AVChromaLocation location); /** + * @return the AVChromaLocation value for name or an AVError if not found. + */ +int av_chroma_location_from_name(const char *name); + +/** * Return the pixel format corresponding to name. * * If there is no pixel format with name name, then looks for a diff --git a/media/ffvpx/libavutil/pixfmt.h b/media/ffvpx/libavutil/pixfmt.h index 7a3f68be7e..24889c8e52 100644 --- a/media/ffvpx/libavutil/pixfmt.h +++ b/media/ffvpx/libavutil/pixfmt.h @@ -240,7 +240,7 @@ enum AVPixelFormat { */ AV_PIX_FMT_MMAL, - AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer + AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11 via old API, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer /** * HW acceleration through CUDA. data[i] contain CUdeviceptr pointers @@ -306,6 +306,41 @@ enum AVPixelFormat { AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec + AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian + AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian + AV_PIX_FMT_GRAY10BE, ///< Y , 10bpp, big-endian + AV_PIX_FMT_GRAY10LE, ///< Y , 10bpp, little-endian + + AV_PIX_FMT_P016LE, ///< like NV12, with 16bpp per component, little-endian + AV_PIX_FMT_P016BE, ///< like NV12, with 16bpp per component, big-endian + + /** + * Hardware surfaces for Direct3D11. + * + * This is preferred over the legacy AV_PIX_FMT_D3D11VA_VLD. The new D3D11 + * hwaccel API and filtering support AV_PIX_FMT_D3D11 only. + * + * data[0] contains a ID3D11Texture2D pointer, and data[1] contains the + * texture array index of the frame as intptr_t if the ID3D11Texture2D is + * an array texture (or always 0 if it's a normal texture). + */ + AV_PIX_FMT_D3D11, + + AV_PIX_FMT_GRAY9BE, ///< Y , 9bpp, big-endian + AV_PIX_FMT_GRAY9LE, ///< Y , 9bpp, little-endian + + AV_PIX_FMT_GBRPF32BE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, big-endian + AV_PIX_FMT_GBRPF32LE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, little-endian + AV_PIX_FMT_GBRAPF32BE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, big-endian + AV_PIX_FMT_GBRAPF32LE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, little-endian + + /** + * DRM-managed buffers exposed through PRIME buffer sharing. + * + * data[0] points to an AVDRMFrameDescriptor. + */ + AV_PIX_FMT_DRM_PRIME, + 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 }; @@ -322,6 +357,9 @@ enum AVPixelFormat { #define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0) #define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0) +#define AV_PIX_FMT_GRAY9 AV_PIX_FMT_NE(GRAY9BE, GRAY9LE) +#define AV_PIX_FMT_GRAY10 AV_PIX_FMT_NE(GRAY10BE, GRAY10LE) +#define AV_PIX_FMT_GRAY12 AV_PIX_FMT_NE(GRAY12BE, GRAY12LE) #define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) #define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) #define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) @@ -367,6 +405,8 @@ enum AVPixelFormat { #define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE) #define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE) +#define AV_PIX_FMT_GBRPF32 AV_PIX_FMT_NE(GBRPF32BE, GBRPF32LE) +#define AV_PIX_FMT_GBRAPF32 AV_PIX_FMT_NE(GBRAPF32BE, GBRAPF32LE) #define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) #define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) @@ -382,9 +422,11 @@ enum AVPixelFormat { #define AV_PIX_FMT_NV20 AV_PIX_FMT_NE(NV20BE, NV20LE) #define AV_PIX_FMT_AYUV64 AV_PIX_FMT_NE(AYUV64BE, AYUV64LE) #define AV_PIX_FMT_P010 AV_PIX_FMT_NE(P010BE, P010LE) +#define AV_PIX_FMT_P016 AV_PIX_FMT_NE(P016BE, P016LE) /** * Chromaticity coordinates of the source primaries. + * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.1. */ enum AVColorPrimaries { AVCOL_PRI_RESERVED0 = 0, @@ -398,14 +440,17 @@ enum AVColorPrimaries { AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 - AVCOL_PRI_SMPTEST428_1 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) - AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) - AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 D65 (2010) + AVCOL_PRI_SMPTE428 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) / DCI P3 + AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 + AVCOL_PRI_JEDEC_P22 = 22, ///< JEDEC P22 phosphors AVCOL_PRI_NB ///< Not part of ABI }; /** * Color Transfer Characteristic. + * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.2. */ enum AVColorTransferCharacteristic { AVCOL_TRC_RESERVED0 = 0, @@ -424,14 +469,17 @@ enum AVColorTransferCharacteristic { AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10-bit system AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12-bit system - AVCOL_TRC_SMPTEST2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems - AVCOL_TRC_SMPTEST428_1 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTE2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + AVCOL_TRC_SMPTE428 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, AVCOL_TRC_ARIB_STD_B67 = 18, ///< ARIB STD-B67, known as "Hybrid log-gamma" AVCOL_TRC_NB ///< Not part of ABI }; /** * YUV colorspace type. + * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.3. */ enum AVColorSpace { AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) @@ -442,14 +490,16 @@ enum AVColorSpace { AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC AVCOL_SPC_SMPTE240M = 7, ///< functionally identical to above - AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCGCO = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system + AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system + AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp AVCOL_SPC_NB ///< Not part of ABI }; -#define AVCOL_SPC_YCGCO AVCOL_SPC_YCOCG - /** * MPEG vs JPEG YUV range. diff --git a/media/ffvpx/libavutil/reverse.h b/media/ffvpx/libavutil/reverse.h new file mode 100644 index 0000000000..4eb6123932 --- /dev/null +++ b/media/ffvpx/libavutil/reverse.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REVERSE_H +#define AVUTIL_REVERSE_H + +#include <stdint.h> + +extern const uint8_t ff_reverse[256]; + +#endif /* AVUTIL_REVERSE_H */ diff --git a/media/ffvpx/libavutil/slicethread.c b/media/ffvpx/libavutil/slicethread.c new file mode 100644 index 0000000000..c43f87a2aa --- /dev/null +++ b/media/ffvpx/libavutil/slicethread.c @@ -0,0 +1,259 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdatomic.h> +#include "slicethread.h" +#include "mem.h" +#include "thread.h" +#include "avassert.h" + +#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS + +typedef struct WorkerContext { + AVSliceThread *ctx; + pthread_mutex_t mutex; + pthread_cond_t cond; + pthread_t thread; + int done; +} WorkerContext; + +struct AVSliceThread { + WorkerContext *workers; + int nb_threads; + int nb_active_threads; + int nb_jobs; + + atomic_uint first_job; + atomic_uint current_job; + pthread_mutex_t done_mutex; + pthread_cond_t done_cond; + int done; + int finished; + + void *priv; + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads); + void (*main_func)(void *priv); +}; + +static int run_jobs(AVSliceThread *ctx) +{ + unsigned nb_jobs = ctx->nb_jobs; + unsigned nb_active_threads = ctx->nb_active_threads; + unsigned first_job = atomic_fetch_add_explicit(&ctx->first_job, 1, memory_order_acq_rel); + unsigned current_job = first_job; + + do { + ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads); + } while ((current_job = atomic_fetch_add_explicit(&ctx->current_job, 1, memory_order_acq_rel)) < nb_jobs); + + return current_job == nb_jobs + nb_active_threads - 1; +} + +static void *attribute_align_arg thread_worker(void *v) +{ + WorkerContext *w = v; + AVSliceThread *ctx = w->ctx; + + pthread_mutex_lock(&w->mutex); + pthread_cond_signal(&w->cond); + + while (1) { + w->done = 1; + while (w->done) + pthread_cond_wait(&w->cond, &w->mutex); + + if (ctx->finished) { + pthread_mutex_unlock(&w->mutex); + return NULL; + } + + if (run_jobs(ctx)) { + pthread_mutex_lock(&ctx->done_mutex); + ctx->done = 1; + pthread_cond_signal(&ctx->done_cond); + pthread_mutex_unlock(&ctx->done_mutex); + } + } +} + +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads) +{ + AVSliceThread *ctx; + int nb_workers, i; + +#if HAVE_W32THREADS + w32thread_init(); +#endif + + av_assert0(nb_threads >= 0); + if (!nb_threads) { + int nb_cpus = av_cpu_count(); + if (nb_cpus > 1) + nb_threads = nb_cpus + 1; + else + nb_threads = 1; + } + + nb_workers = nb_threads; + if (!main_func) + nb_workers--; + + *pctx = ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + if (nb_workers && !(ctx->workers = av_calloc(nb_workers, sizeof(*ctx->workers)))) { + av_freep(pctx); + return AVERROR(ENOMEM); + } + + ctx->priv = priv; + ctx->worker_func = worker_func; + ctx->main_func = main_func; + ctx->nb_threads = nb_threads; + ctx->nb_active_threads = 0; + ctx->nb_jobs = 0; + ctx->finished = 0; + + atomic_init(&ctx->first_job, 0); + atomic_init(&ctx->current_job, 0); + pthread_mutex_init(&ctx->done_mutex, NULL); + pthread_cond_init(&ctx->done_cond, NULL); + ctx->done = 0; + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + int ret; + w->ctx = ctx; + pthread_mutex_init(&w->mutex, NULL); + pthread_cond_init(&w->cond, NULL); + pthread_mutex_lock(&w->mutex); + w->done = 0; + + if (ret = pthread_create(&w->thread, NULL, thread_worker, w)) { + ctx->nb_threads = main_func ? i : i + 1; + pthread_mutex_unlock(&w->mutex); + pthread_cond_destroy(&w->cond); + pthread_mutex_destroy(&w->mutex); + avpriv_slicethread_free(pctx); + return AVERROR(ret); + } + + while (!w->done) + pthread_cond_wait(&w->cond, &w->mutex); + pthread_mutex_unlock(&w->mutex); + } + + return nb_threads; +} + +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) +{ + int nb_workers, i, is_last = 0; + + av_assert0(nb_jobs > 0); + ctx->nb_jobs = nb_jobs; + ctx->nb_active_threads = FFMIN(nb_jobs, ctx->nb_threads); + atomic_store_explicit(&ctx->first_job, 0, memory_order_relaxed); + atomic_store_explicit(&ctx->current_job, ctx->nb_active_threads, memory_order_relaxed); + nb_workers = ctx->nb_active_threads; + if (!ctx->main_func || !execute_main) + nb_workers--; + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_mutex_lock(&w->mutex); + w->done = 0; + pthread_cond_signal(&w->cond); + pthread_mutex_unlock(&w->mutex); + } + + if (ctx->main_func && execute_main) + ctx->main_func(ctx->priv); + else + is_last = run_jobs(ctx); + + if (!is_last) { + pthread_mutex_lock(&ctx->done_mutex); + while (!ctx->done) + pthread_cond_wait(&ctx->done_cond, &ctx->done_mutex); + ctx->done = 0; + pthread_mutex_unlock(&ctx->done_mutex); + } +} + +void avpriv_slicethread_free(AVSliceThread **pctx) +{ + AVSliceThread *ctx; + int nb_workers, i; + + if (!pctx || !*pctx) + return; + + ctx = *pctx; + nb_workers = ctx->nb_threads; + if (!ctx->main_func) + nb_workers--; + + ctx->finished = 1; + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_mutex_lock(&w->mutex); + w->done = 0; + pthread_cond_signal(&w->cond); + pthread_mutex_unlock(&w->mutex); + } + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_join(w->thread, NULL); + pthread_cond_destroy(&w->cond); + pthread_mutex_destroy(&w->mutex); + } + + pthread_cond_destroy(&ctx->done_cond); + pthread_mutex_destroy(&ctx->done_mutex); + av_freep(&ctx->workers); + av_freep(pctx); +} + +#else /* HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS32THREADS */ + +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads) +{ + *pctx = NULL; + return AVERROR(EINVAL); +} + +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) +{ + av_assert0(0); +} + +void avpriv_slicethread_free(AVSliceThread **pctx) +{ + av_assert0(!pctx || !*pctx); +} + +#endif /* HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS32THREADS */ diff --git a/media/ffvpx/libavutil/slicethread.h b/media/ffvpx/libavutil/slicethread.h new file mode 100644 index 0000000000..f6f6f302c4 --- /dev/null +++ b/media/ffvpx/libavutil/slicethread.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SLICETHREAD_H +#define AVUTIL_SLICETHREAD_H + +typedef struct AVSliceThread AVSliceThread; + +/** + * Create slice threading context. + * @param pctx slice threading context returned here + * @param priv private pointer to be passed to callback function + * @param worker_func callback function to be executed + * @param main_func special callback function, called from main thread, may be NULL + * @param nb_threads number of threads, 0 for automatic, must be >= 0 + * @return return number of threads or negative AVERROR on failure + */ +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads); + +/** + * Execute slice threading. + * @param ctx slice threading context + * @param nb_jobs number of jobs, must be > 0 + * @param execute_main also execute main_func + */ +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main); + +/** + * Destroy slice threading context. + * @param pctx pointer to context + */ +void avpriv_slicethread_free(AVSliceThread **pctx); + +#endif diff --git a/media/ffvpx/libavutil/thread.h b/media/ffvpx/libavutil/thread.h index 32ddf40365..f108e20052 100644 --- a/media/ffvpx/libavutil/thread.h +++ b/media/ffvpx/libavutil/thread.h @@ -26,8 +26,6 @@ #if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS -#define USE_ATOMICS 0 - #if HAVE_PTHREADS #include <pthread.h> @@ -38,8 +36,11 @@ #define ASSERT_PTHREAD_NORET(func, ...) do { \ int ret = func(__VA_ARGS__); \ if (ret) { \ + char errbuf[AV_ERROR_MAX_STRING_SIZE] = ""; \ av_log(NULL, AV_LOG_FATAL, AV_STRINGIFY(func) \ - " failed with error: %s\n", av_err2str(AVERROR(ret))); \ + " failed with error: %s\n", \ + av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, \ + AVERROR(ret))); \ abort(); \ } \ } while (0) @@ -146,8 +147,6 @@ static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_ #else -#define USE_ATOMICS 1 - #define AVMutex char #define ff_mutex_init(mutex, attr) (0) diff --git a/media/ffvpx/libavutil/threadmessage.c b/media/ffvpx/libavutil/threadmessage.c index 7c5cd2463c..872e9392b1 100644 --- a/media/ffvpx/libavutil/threadmessage.c +++ b/media/ffvpx/libavutil/threadmessage.c @@ -69,7 +69,7 @@ int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, pthread_cond_destroy(&rmq->cond_recv); pthread_mutex_destroy(&rmq->lock); av_free(rmq); - return AVERROR(ret); + return AVERROR(ENOMEM); } rmq->elsize = elsize; *mq = rmq; diff --git a/media/ffvpx/libavutil/time.c b/media/ffvpx/libavutil/time.c index 69419e6f38..80d1faf264 100644 --- a/media/ffvpx/libavutil/time.c +++ b/media/ffvpx/libavutil/time.c @@ -56,17 +56,25 @@ int64_t av_gettime(void) int64_t av_gettime_relative(void) { #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; -#else - return av_gettime() + 42 * 60 * 60 * INT64_C(1000000); +#ifdef __APPLE__ + if (clock_gettime) +#endif + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + } #endif + return av_gettime() + 42 * 60 * 60 * INT64_C(1000000); } int av_gettime_relative_is_monotonic(void) { #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) +#ifdef __APPLE__ + if (!clock_gettime) + return 0; +#endif return 1; #else return 0; diff --git a/media/ffvpx/libavutil/timecode.c b/media/ffvpx/libavutil/timecode.c index fa92df1ef9..c0c67c8478 100644 --- a/media/ffvpx/libavutil/timecode.c +++ b/media/ffvpx/libavutil/timecode.c @@ -129,7 +129,8 @@ char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_ char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit) { - snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u", + snprintf(buf, AV_TIMECODE_STR_SIZE, + "%02"PRIu32":%02"PRIu32":%02"PRIu32"%c%02"PRIu32, tc25bit>>19 & 0x1f, // 5-bit hours tc25bit>>13 & 0x3f, // 6-bit minutes tc25bit>>6 & 0x3f, // 6-bit seconds diff --git a/media/ffvpx/libavutil/timecode.h b/media/ffvpx/libavutil/timecode.h index 56e3975fd8..37c1361bc2 100644 --- a/media/ffvpx/libavutil/timecode.h +++ b/media/ffvpx/libavutil/timecode.h @@ -30,7 +30,7 @@ #include <stdint.h> #include "rational.h" -#define AV_TIMECODE_STR_SIZE 16 +#define AV_TIMECODE_STR_SIZE 23 enum AVTimecodeFlag { AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame diff --git a/media/ffvpx/libavutil/timer.h b/media/ffvpx/libavutil/timer.h index ed3b047870..f7ab455df2 100644 --- a/media/ffvpx/libavutil/timer.h +++ b/media/ffvpx/libavutil/timer.h @@ -26,12 +26,22 @@ #ifndef AVUTIL_TIMER_H #define AVUTIL_TIMER_H +#include "config.h" + +#if CONFIG_LINUX_PERF +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include <unistd.h> // read(3) +# include <sys/ioctl.h> +# include <asm/unistd.h> +# include <linux/perf_event.h> +#endif + #include <stdlib.h> #include <stdint.h> #include <inttypes.h> -#include "config.h" - #if HAVE_MACH_MACH_TIME_H #include <mach/mach_time.h> #endif @@ -60,23 +70,17 @@ # define FF_TIMER_UNITS "UNITS" #endif -#ifdef AV_READ_TIME -#define START_TIMER \ - uint64_t tend; \ - uint64_t tstart = AV_READ_TIME(); \ - -#define STOP_TIMER(id) \ - tend = AV_READ_TIME(); \ +#define TIMER_REPORT(id, tdiff) \ { \ static uint64_t tsum = 0; \ static int tcount = 0; \ static int tskip_count = 0; \ static int thistogram[32] = {0}; \ - thistogram[av_log2(tend - tstart)]++; \ - if (tcount < 2 || \ - tend - tstart < 8 * tsum / tcount || \ - tend - tstart < 2000) { \ - tsum+= tend - tstart; \ + thistogram[av_log2(tdiff)]++; \ + if (tcount < 2 || \ + (tdiff) < 8 * tsum / tcount || \ + (tdiff) < 2000) { \ + tsum += (tdiff); \ tcount++; \ } else \ tskip_count++; \ @@ -90,6 +94,45 @@ av_log(NULL, AV_LOG_ERROR, "\n"); \ } \ } + +#if CONFIG_LINUX_PERF + +#define START_TIMER \ + static int linux_perf_fd; \ + uint64_t tperf; \ + if (!linux_perf_fd) { \ + struct perf_event_attr attr = { \ + .type = PERF_TYPE_HARDWARE, \ + .size = sizeof(struct perf_event_attr), \ + .config = PERF_COUNT_HW_CPU_CYCLES, \ + .disabled = 1, \ + .exclude_kernel = 1, \ + .exclude_hv = 1, \ + }; \ + linux_perf_fd = syscall(__NR_perf_event_open, &attr, \ + 0, -1, -1, 0); \ + } \ + if (linux_perf_fd == -1) { \ + av_log(NULL, AV_LOG_ERROR, "perf_event_open failed: %s\n", \ + av_err2str(AVERROR(errno))); \ + } else { \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_RESET, 0); \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_ENABLE, 0); \ + } + +#define STOP_TIMER(id) \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_DISABLE, 0); \ + read(linux_perf_fd, &tperf, sizeof(tperf)); \ + TIMER_REPORT(id, tperf) + +#elif defined(AV_READ_TIME) +#define START_TIMER \ + uint64_t tend; \ + uint64_t tstart = AV_READ_TIME(); \ + +#define STOP_TIMER(id) \ + tend = AV_READ_TIME(); \ + TIMER_REPORT(id, tend - tstart) #else #define START_TIMER #define STOP_TIMER(id) { } diff --git a/media/ffvpx/libavutil/utils.c b/media/ffvpx/libavutil/utils.c index 36e4dd5fdb..2c170db2e1 100644 --- a/media/ffvpx/libavutil/utils.c +++ b/media/ffvpx/libavutil/utils.c @@ -121,6 +121,29 @@ unsigned av_int_list_length_for_size(unsigned elsize, return i; } +char *av_fourcc_make_string(char *buf, uint32_t fourcc) +{ + int i; + char *orig_buf = buf; + size_t buf_size = AV_FOURCC_MAX_STRING_SIZE; + + for (i = 0; i < 4; i++) { + const int c = fourcc & 0xff; + const int print_chr = (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c && strchr(". -_", c)); + const int len = snprintf(buf, buf_size, print_chr ? "%c" : "[%d]", c); + if (len < 0) + break; + buf += len; + buf_size = buf_size > len ? buf_size - len : 0; + fourcc >>= 8; + } + + return orig_buf; +} + AVRational av_get_time_base_q(void) { return (AVRational){1, AV_TIME_BASE}; @@ -129,7 +152,7 @@ AVRational av_get_time_base_q(void) void av_assert0_fpu(void) { #if HAVE_MMX_INLINE uint16_t state[14]; - __asm volatile ( + __asm__ volatile ( "fstenv %0 \n\t" : "+m" (state) : diff --git a/media/ffvpx/libavutil/version.h b/media/ffvpx/libavutil/version.h index bdd310f855..f594dc0691 100644 --- a/media/ffvpx/libavutil/version.h +++ b/media/ffvpx/libavutil/version.h @@ -78,8 +78,9 @@ * @{ */ + #define LIBAVUTIL_VERSION_MAJOR 55 -#define LIBAVUTIL_VERSION_MINOR 34 +#define LIBAVUTIL_VERSION_MINOR 78 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -135,6 +136,9 @@ #ifndef FF_API_PKT_PTS #define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 56) #endif +#ifndef FF_API_CRYPTO_SIZE_T +#define FF_API_CRYPTO_SIZE_T (LIBAVUTIL_VERSION_MAJOR < 56) +#endif /** diff --git a/media/ffvpx/libavutil/x86/cpu.c b/media/ffvpx/libavutil/x86/cpu.c index f3a49c6772..f33088c8c7 100644 --- a/media/ffvpx/libavutil/x86/cpu.c +++ b/media/ffvpx/libavutil/x86/cpu.c @@ -28,7 +28,7 @@ #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" -#if HAVE_YASM +#if HAVE_X86ASM #define cpuid(index, eax, ebx, ecx, edx) \ ff_cpu_cpuid(index, &eax, &ebx, &ecx, &edx) @@ -66,7 +66,7 @@ #define cpuid_test() 1 -#elif HAVE_YASM +#elif HAVE_X86ASM #define cpuid_test ff_cpu_cpuid_test @@ -221,9 +221,42 @@ int ff_get_cpu_flags_x86(void) * functions on the Atom. */ if (family == 6 && model == 28) rval |= AV_CPU_FLAG_ATOM; + + /* Conroe has a slow shuffle unit. Check the model number to ensure not + * to include crippled low-end Penryns and Nehalems that lack SSE4. */ + if ((rval & AV_CPU_FLAG_SSSE3) && !(rval & AV_CPU_FLAG_SSE4) && + family == 6 && model < 23) + rval |= AV_CPU_FLAG_SSSE3SLOW; } #endif /* cpuid */ return rval; } + +size_t ff_get_cpu_max_align_x86(void) +{ + int flags = av_get_cpu_flags(); + + if (flags & (AV_CPU_FLAG_AVX2 | + AV_CPU_FLAG_AVX | + AV_CPU_FLAG_XOP | + AV_CPU_FLAG_FMA4 | + AV_CPU_FLAG_FMA3 | + AV_CPU_FLAG_AVXSLOW)) + return 32; + if (flags & (AV_CPU_FLAG_AESNI | + AV_CPU_FLAG_SSE42 | + AV_CPU_FLAG_SSE4 | + AV_CPU_FLAG_SSSE3 | + AV_CPU_FLAG_SSE3 | + AV_CPU_FLAG_SSE2 | + AV_CPU_FLAG_SSE | + AV_CPU_FLAG_ATOM | + AV_CPU_FLAG_SSSE3SLOW | + AV_CPU_FLAG_SSE3SLOW | + AV_CPU_FLAG_SSE2SLOW)) + return 16; + + return 8; +} diff --git a/media/ffvpx/libavutil/x86/cpu.h b/media/ffvpx/libavutil/x86/cpu.h index f171037f1c..309b8e746c 100644 --- a/media/ffvpx/libavutil/x86/cpu.h +++ b/media/ffvpx/libavutil/x86/cpu.h @@ -38,6 +38,8 @@ #define X86_SSE3_FAST(flags) CPUEXT_FAST(flags, SSE3) #define X86_SSE3_SLOW(flags) CPUEXT_SLOW(flags, SSE3) #define X86_SSSE3(flags) CPUEXT(flags, SSSE3) +#define X86_SSSE3_FAST(flags) CPUEXT_FAST(flags, SSSE3) +#define X86_SSSE3_SLOW(flags) CPUEXT_SLOW(flags, SSSE3) #define X86_SSE4(flags) CPUEXT(flags, SSE4) #define X86_SSE42(flags) CPUEXT(flags, SSE42) #define X86_AVX(flags) CPUEXT(flags, AVX) @@ -61,6 +63,8 @@ #define EXTERNAL_SSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSE3) #define EXTERNAL_SSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSE3) #define EXTERNAL_SSSE3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSSE3) #define EXTERNAL_SSE4(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE4) #define EXTERNAL_SSE42(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE42) #define EXTERNAL_AVX(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX) @@ -88,6 +92,8 @@ #define INLINE_SSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSE3) #define INLINE_SSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSE3) #define INLINE_SSSE3(flags) CPUEXT_SUFFIX(flags, _INLINE, SSSE3) +#define INLINE_SSSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSSE3) +#define INLINE_SSSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSSE3) #define INLINE_SSE4(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE4) #define INLINE_SSE42(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE42) #define INLINE_AVX(flags) CPUEXT_SUFFIX(flags, _INLINE, AVX) diff --git a/media/ffvpx/libavutil/x86/emms.asm b/media/ffvpx/libavutil/x86/emms.asm index 0aad34af3f..8611762d73 100644 --- a/media/ffvpx/libavutil/x86/emms.asm +++ b/media/ffvpx/libavutil/x86/emms.asm @@ -23,8 +23,8 @@ SECTION .text ;----------------------------------------------------------------------------- -; void avpriv_emms_yasm(void) +; void avpriv_emms_asm(void) ;----------------------------------------------------------------------------- -cvisible emms_yasm, 0, 0 +cvisible emms_asm, 0, 0 emms RET diff --git a/media/ffvpx/libavutil/x86/emms.h b/media/ffvpx/libavutil/x86/emms.h index 42c18e2953..c21e34b451 100644 --- a/media/ffvpx/libavutil/x86/emms.h +++ b/media/ffvpx/libavutil/x86/emms.h @@ -23,7 +23,7 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" -void avpriv_emms_yasm(void); +void avpriv_emms_asm(void); #if HAVE_MMX_INLINE # define emms_c emms_c @@ -49,7 +49,7 @@ static av_always_inline void emms_c(void) # include <mmintrin.h> # define emms_c _mm_empty #elif HAVE_MMX_EXTERNAL -# define emms_c avpriv_emms_yasm +# define emms_c avpriv_emms_asm #endif /* HAVE_MMX_INLINE */ #endif /* AVUTIL_X86_EMMS_H */ diff --git a/media/ffvpx/libavutil/x86/float_dsp.asm b/media/ffvpx/libavutil/x86/float_dsp.asm index 021ff03c87..06d2d2cfd1 100644 --- a/media/ffvpx/libavutil/x86/float_dsp.asm +++ b/media/ffvpx/libavutil/x86/float_dsp.asm @@ -22,6 +22,9 @@ %include "x86util.asm" +SECTION_RODATA 32 +pd_reverse: dd 7, 6, 5, 4, 3, 2, 1, 0 + SECTION .text ;----------------------------------------------------------------------------- @@ -149,6 +152,69 @@ INIT_XMM sse VECTOR_FMUL_SCALAR ;------------------------------------------------------------------------------ +; void ff_vector_dmac_scalar(double *dst, const double *src, double mul, +; int len) +;------------------------------------------------------------------------------ + +%macro VECTOR_DMAC_SCALAR 0 +%if ARCH_X86_32 +cglobal vector_dmac_scalar, 2,4,5, dst, src, mul, len, lenaddr + mov lenq, lenaddrm + VBROADCASTSD m0, mulm +%else +%if UNIX64 +cglobal vector_dmac_scalar, 3,3,5, dst, src, len +%else +cglobal vector_dmac_scalar, 4,4,5, dst, src, mul, len + SWAP 0, 2 +%endif + movlhps xm0, xm0 +%if cpuflag(avx) + vinsertf128 m0, m0, xm0, 1 +%endif +%endif + lea lenq, [lend*8-mmsize*4] +.loop: +%if cpuflag(fma3) + movaps m1, [dstq+lenq] + movaps m2, [dstq+lenq+1*mmsize] + movaps m3, [dstq+lenq+2*mmsize] + movaps m4, [dstq+lenq+3*mmsize] + fmaddpd m1, m0, [srcq+lenq], m1 + fmaddpd m2, m0, [srcq+lenq+1*mmsize], m2 + fmaddpd m3, m0, [srcq+lenq+2*mmsize], m3 + fmaddpd m4, m0, [srcq+lenq+3*mmsize], m4 +%else ; cpuflag + mulpd m1, m0, [srcq+lenq] + mulpd m2, m0, [srcq+lenq+1*mmsize] + mulpd m3, m0, [srcq+lenq+2*mmsize] + mulpd m4, m0, [srcq+lenq+3*mmsize] + addpd m1, m1, [dstq+lenq] + addpd m2, m2, [dstq+lenq+1*mmsize] + addpd m3, m3, [dstq+lenq+2*mmsize] + addpd m4, m4, [dstq+lenq+3*mmsize] +%endif ; cpuflag + movaps [dstq+lenq], m1 + movaps [dstq+lenq+1*mmsize], m2 + movaps [dstq+lenq+2*mmsize], m3 + movaps [dstq+lenq+3*mmsize], m4 + sub lenq, mmsize*4 + jge .loop + REP_RET +%endmacro + +INIT_XMM sse2 +VECTOR_DMAC_SCALAR +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_DMAC_SCALAR +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +VECTOR_DMAC_SCALAR +%endif + +;------------------------------------------------------------------------------ ; void ff_vector_dmul_scalar(double *dst, const double *src, double mul, ; int len) ;------------------------------------------------------------------------------ @@ -177,8 +243,8 @@ cglobal vector_dmul_scalar, 4,4,3, dst, src, mul, len .loop: mulpd m1, m0, [srcq+lenq ] mulpd m2, m0, [srcq+lenq+mmsize] - mova [dstq+lenq ], m1 - mova [dstq+lenq+mmsize], m2 + movaps [dstq+lenq ], m1 + movaps [dstq+lenq+mmsize], m2 sub lenq, 2*mmsize jge .loop REP_RET @@ -296,10 +362,16 @@ VECTOR_FMUL_ADD ;----------------------------------------------------------------------------- %macro VECTOR_FMUL_REVERSE 0 cglobal vector_fmul_reverse, 4,4,2, dst, src0, src1, len +%if cpuflag(avx2) + movaps m2, [pd_reverse] +%endif lea lenq, [lend*4 - 2*mmsize] ALIGN 16 .loop: -%if cpuflag(avx) +%if cpuflag(avx2) + vpermps m0, m2, [src1q] + vpermps m1, m2, [src1q+mmsize] +%elif cpuflag(avx) vmovaps xmm0, [src1q + 16] vinsertf128 m0, m0, [src1q], 1 vshufps m0, m0, m0, q0123 @@ -314,8 +386,8 @@ ALIGN 16 %endif mulps m0, m0, [src0q + lenq + mmsize] mulps m1, m1, [src0q + lenq] - mova [dstq + lenq + mmsize], m0 - mova [dstq + lenq], m1 + movaps [dstq + lenq + mmsize], m0 + movaps [dstq + lenq], m1 add src1q, 2*mmsize sub lenq, 2*mmsize jge .loop @@ -328,6 +400,10 @@ VECTOR_FMUL_REVERSE INIT_YMM avx VECTOR_FMUL_REVERSE %endif +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +VECTOR_FMUL_REVERSE +%endif ; float scalarproduct_float_sse(const float *v1, const float *v2, int len) INIT_XMM sse diff --git a/media/ffvpx/libavutil/x86/float_dsp_init.c b/media/ffvpx/libavutil/x86/float_dsp_init.c index c836a78e1b..122087a196 100644 --- a/media/ffvpx/libavutil/x86/float_dsp_init.c +++ b/media/ffvpx/libavutil/x86/float_dsp_init.c @@ -39,6 +39,13 @@ void ff_vector_fmac_scalar_fma3(float *dst, const float *src, float mul, void ff_vector_fmul_scalar_sse(float *dst, const float *src, float mul, int len); +void ff_vector_dmac_scalar_sse2(double *dst, const double *src, double mul, + int len); +void ff_vector_dmac_scalar_avx(double *dst, const double *src, double mul, + int len); +void ff_vector_dmac_scalar_fma3(double *dst, const double *src, double mul, + int len); + void ff_vector_dmul_scalar_sse2(double *dst, const double *src, double mul, int len); void ff_vector_dmul_scalar_avx(double *dst, const double *src, @@ -60,10 +67,12 @@ void ff_vector_fmul_reverse_sse(float *dst, const float *src0, const float *src1, int len); void ff_vector_fmul_reverse_avx(float *dst, const float *src0, const float *src1, int len); +void ff_vector_fmul_reverse_avx2(float *dst, const float *src0, + const float *src1, int len); float ff_scalarproduct_float_sse(const float *v1, const float *v2, int order); -void ff_butterflies_float_sse(float *src0, float *src1, int len); +void ff_butterflies_float_sse(float *av_restrict src0, float *av_restrict src1, int len); av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) { @@ -83,17 +92,23 @@ av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) fdsp->butterflies_float = ff_butterflies_float_sse; } if (EXTERNAL_SSE2(cpu_flags)) { + fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_sse2; fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_sse2; } if (EXTERNAL_AVX_FAST(cpu_flags)) { fdsp->vector_fmul = ff_vector_fmul_avx; fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_avx; fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_avx; + fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_avx; fdsp->vector_fmul_add = ff_vector_fmul_add_avx; fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx; } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx2; + } if (EXTERNAL_FMA3_FAST(cpu_flags)) { fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_fma3; fdsp->vector_fmul_add = ff_vector_fmul_add_fma3; + fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_fma3; } } diff --git a/media/ffvpx/libavutil/x86/imgutils.asm b/media/ffvpx/libavutil/x86/imgutils.asm new file mode 100644 index 0000000000..3cca56cdca --- /dev/null +++ b/media/ffvpx/libavutil/x86/imgutils.asm @@ -0,0 +1,53 @@ +;***************************************************************************** +;* Copyright 2016 Anton Khirnov +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION .text + +INIT_XMM sse4 +cglobal image_copy_plane_uc_from, 6, 7, 4, dst, dst_linesize, src, src_linesize, bw, height, rowpos + add dstq, bwq + add srcq, bwq + neg bwq + +.row_start: + mov rowposq, bwq + +.loop: + movntdqa m0, [srcq + rowposq + 0 * mmsize] + movntdqa m1, [srcq + rowposq + 1 * mmsize] + movntdqa m2, [srcq + rowposq + 2 * mmsize] + movntdqa m3, [srcq + rowposq + 3 * mmsize] + + mova [dstq + rowposq + 0 * mmsize], m0 + mova [dstq + rowposq + 1 * mmsize], m1 + mova [dstq + rowposq + 2 * mmsize], m2 + mova [dstq + rowposq + 3 * mmsize], m3 + + add rowposq, 4 * mmsize + jnz .loop + + add srcq, src_linesizeq + add dstq, dst_linesizeq + dec heightd + jnz .row_start + + RET diff --git a/media/ffvpx/libavutil/x86/imgutils_init.c b/media/ffvpx/libavutil/x86/imgutils_init.c new file mode 100644 index 0000000000..4ea398205e --- /dev/null +++ b/media/ffvpx/libavutil/x86/imgutils_init.c @@ -0,0 +1,49 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> + +#include "libavutil/cpu.h" +#include "libavutil/error.h" +#include "libavutil/imgutils.h" +#include "libavutil/imgutils_internal.h" +#include "libavutil/internal.h" + +#include "cpu.h" + +void ff_image_copy_plane_uc_from_sse4(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height); + +int ff_image_copy_plane_uc_from_x86(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + int cpu_flags = av_get_cpu_flags(); + ptrdiff_t bw_aligned = FFALIGN(bytewidth, 64); + + if (EXTERNAL_SSE4(cpu_flags) && + bw_aligned <= dst_linesize && bw_aligned <= src_linesize) + ff_image_copy_plane_uc_from_sse4(dst, dst_linesize, src, src_linesize, + bw_aligned, height); + else + return AVERROR(ENOSYS); + + return 0; +} diff --git a/media/ffvpx/libavutil/x86/moz.build b/media/ffvpx/libavutil/x86/moz.build index 1d1a6ca677..b56ed75ead 100644 --- a/media/ffvpx/libavutil/x86/moz.build +++ b/media/ffvpx/libavutil/x86/moz.build @@ -12,6 +12,8 @@ SOURCES += [ 'fixed_dsp_init.c', 'float_dsp.asm', 'float_dsp_init.c', + 'imgutils.asm', + 'imgutils_init.c', 'lls.asm', 'lls_init.c' ] diff --git a/media/ffvpx/libavutil/x86/x86inc.asm b/media/ffvpx/libavutil/x86/x86inc.asm index b2e9c60195..6a054a3e09 100644 --- a/media/ffvpx/libavutil/x86/x86inc.asm +++ b/media/ffvpx/libavutil/x86/x86inc.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* x86inc.asm: x264asm abstraction layer ;***************************************************************************** -;* Copyright (C) 2005-2016 x264 project +;* Copyright (C) 2005-2017 x264 project ;* ;* Authors: Loren Merritt <lorenm@u.washington.edu> ;* Anton Mitrofanov <BugMaster@narod.ru> @@ -87,7 +87,9 @@ ; keep supporting OS/2. %macro SECTION_RODATA 0-1 16 %ifidn __OUTPUT_FORMAT__,aout - section .text + SECTION .text + %elifidn __OUTPUT_FORMAT__,coff + SECTION .text %else SECTION .rodata align=%1 %endif @@ -385,7 +387,14 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %ifnum %1 %if %1 != 0 && required_stack_alignment > STACK_ALIGNMENT %if %1 > 0 + ; Reserve an additional register for storing the original stack pointer, but avoid using + ; eax/rax for this purpose since it can potentially get overwritten as a return value. %assign regs_used (regs_used + 1) + %if ARCH_X86_64 && regs_used == 7 + %assign regs_used 8 + %elif ARCH_X86_64 == 0 && regs_used == 1 + %assign regs_used 2 + %endif %endif %if ARCH_X86_64 && regs_used < 5 + UNIX64 * 3 ; Ensure that we don't clobber any registers containing arguments. For UNIX64 we also preserve r6 (rax) @@ -419,10 +428,10 @@ DECLARE_REG 7, rdi, 64 DECLARE_REG 8, rsi, 72 DECLARE_REG 9, rbx, 80 DECLARE_REG 10, rbp, 88 -DECLARE_REG 11, R12, 96 -DECLARE_REG 12, R13, 104 -DECLARE_REG 13, R14, 112 -DECLARE_REG 14, R15, 120 +DECLARE_REG 11, R14, 96 +DECLARE_REG 12, R15, 104 +DECLARE_REG 13, R12, 112 +DECLARE_REG 14, R13, 120 %macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 @@ -468,41 +477,42 @@ DECLARE_REG 14, R15, 120 WIN64_PUSH_XMM %endmacro -%macro WIN64_RESTORE_XMM_INTERNAL 1 +%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 %%i %%i-1 - movaps xmm %+ %%i, [%1 + (%%i-8)*16 + stack_size + 32] + movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32] %endrep %endif %if stack_size_padded > 0 %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT mov rsp, rstkm %else - add %1, stack_size_padded + add rsp, stack_size_padded %assign %%pad_size stack_size_padded %endif %endif %if xmm_regs_used > 7 - movaps xmm7, [%1 + stack_offset - %%pad_size + 24] + movaps xmm7, [rsp + stack_offset - %%pad_size + 24] %endif %if xmm_regs_used > 6 - movaps xmm6, [%1 + stack_offset - %%pad_size + 8] + movaps xmm6, [rsp + stack_offset - %%pad_size + 8] %endif %endmacro -%macro WIN64_RESTORE_XMM 1 - WIN64_RESTORE_XMM_INTERNAL %1 +%macro WIN64_RESTORE_XMM 0 + WIN64_RESTORE_XMM_INTERNAL %assign stack_offset (stack_offset-stack_size_padded) + %assign stack_size_padded 0 %assign xmm_regs_used 0 %endmacro %define has_epilogue regs_used > 7 || xmm_regs_used > 6 || mmsize == 32 || stack_size > 0 %macro RET 0 - WIN64_RESTORE_XMM_INTERNAL rsp + WIN64_RESTORE_XMM_INTERNAL POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 %if mmsize == 32 vzeroupper @@ -523,10 +533,10 @@ DECLARE_REG 7, R10, 16 DECLARE_REG 8, R11, 24 DECLARE_REG 9, rbx, 32 DECLARE_REG 10, rbp, 40 -DECLARE_REG 11, R12, 48 -DECLARE_REG 12, R13, 56 -DECLARE_REG 13, R14, 64 -DECLARE_REG 14, R15, 72 +DECLARE_REG 11, R14, 48 +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... %assign num_args %1 @@ -618,7 +628,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %if WIN64 == 0 %macro WIN64_SPILL_XMM 1 %endmacro - %macro WIN64_RESTORE_XMM 1 + %macro WIN64_RESTORE_XMM 0 %endmacro %macro WIN64_PUSH_XMM 0 %endmacro @@ -629,7 +639,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 ; We can automatically detect "follows a branch", but not a branch target. ; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.) %macro REP_RET 0 - %if has_epilogue + %if has_epilogue || cpuflag(ssse3) RET %else rep ret @@ -780,25 +790,25 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign cpuflags_sse (1<<4) | cpuflags_mmx2 %assign cpuflags_sse2 (1<<5) | cpuflags_sse %assign cpuflags_sse2slow (1<<6) | cpuflags_sse2 -%assign cpuflags_sse3 (1<<7) | cpuflags_sse2 -%assign cpuflags_ssse3 (1<<8) | cpuflags_sse3 -%assign cpuflags_sse4 (1<<9) | cpuflags_ssse3 -%assign cpuflags_sse42 (1<<10)| cpuflags_sse4 -%assign cpuflags_avx (1<<11)| cpuflags_sse42 -%assign cpuflags_xop (1<<12)| cpuflags_avx -%assign cpuflags_fma4 (1<<13)| cpuflags_avx -%assign cpuflags_fma3 (1<<14)| cpuflags_avx -%assign cpuflags_avx2 (1<<15)| cpuflags_fma3 - -%assign cpuflags_cache32 (1<<16) -%assign cpuflags_cache64 (1<<17) -%assign cpuflags_slowctz (1<<18) -%assign cpuflags_lzcnt (1<<19) -%assign cpuflags_aligned (1<<20) ; not a cpu feature, but a function variant -%assign cpuflags_atom (1<<21) -%assign cpuflags_bmi1 (1<<22)|cpuflags_lzcnt -%assign cpuflags_bmi2 (1<<23)|cpuflags_bmi1 -%assign cpuflags_aesni (1<<24)|cpuflags_sse42 +%assign cpuflags_lzcnt (1<<7) | cpuflags_sse2 +%assign cpuflags_sse3 (1<<8) | cpuflags_sse2 +%assign cpuflags_ssse3 (1<<9) | cpuflags_sse3 +%assign cpuflags_sse4 (1<<10)| cpuflags_ssse3 +%assign cpuflags_sse42 (1<<11)| cpuflags_sse4 +%assign cpuflags_aesni (1<<12)| cpuflags_sse42 +%assign cpuflags_avx (1<<13)| cpuflags_sse42 +%assign cpuflags_xop (1<<14)| cpuflags_avx +%assign cpuflags_fma4 (1<<15)| cpuflags_avx +%assign cpuflags_fma3 (1<<16)| cpuflags_avx +%assign cpuflags_bmi1 (1<<17)| cpuflags_avx|cpuflags_lzcnt +%assign cpuflags_bmi2 (1<<18)| cpuflags_bmi1 +%assign cpuflags_avx2 (1<<19)| cpuflags_fma3|cpuflags_bmi2 + +%assign cpuflags_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) ; Returns a boolean value expressing whether or not the specified cpuflag is enabled. %define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) @@ -1030,7 +1040,11 @@ INIT_XMM ; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't %macro call 1 - call_internal %1 %+ SUFFIX, %1 + %ifid %1 + call_internal %1 %+ SUFFIX, %1 + %else + call %1 + %endif %endmacro %macro call_internal 2 %xdefine %%i %2 diff --git a/media/ffvpx/libavutil/x86/x86util.asm b/media/ffvpx/libavutil/x86/x86util.asm index 44ed750ae5..e1220dfc1a 100644 --- a/media/ffvpx/libavutil/x86/x86util.asm +++ b/media/ffvpx/libavutil/x86/x86util.asm @@ -29,6 +29,21 @@ %include "libavutil/x86/x86inc.asm" +; expands to [base],...,[base+7*stride] +%define PASS8ROWS(base, base3, stride, stride3) \ + [base], [base + stride], [base + 2*stride], [base3], \ + [base3 + stride], [base3 + 2*stride], [base3 + stride3], [base3 + stride*4] + +; Interleave low src0 with low src1 and store in src0, +; interleave high src0 with high src1 and store in src1. +; %1 - types +; %2 - index of the register with src0 +; %3 - index of the register with src1 +; %4 - index of the register for intermediate results +; example for %1 - wd: input: src0: x0 x1 x2 x3 z0 z1 z2 z3 +; src1: y0 y1 y2 y3 q0 q1 q2 q3 +; output: src0: x0 y0 x1 y1 x2 y2 x3 y3 +; src1: z0 q0 z1 q1 z2 q2 z3 q3 %macro SBUTTERFLY 4 %ifidn %1, dqqq vperm2i128 m%4, m%2, m%3, q0301 @@ -56,6 +71,12 @@ SWAP %1, %3, %2 %endmacro +%macro SBUTTERFLYPD 3 + movlhps m%3, m%1, m%2 + movhlps m%2, m%2, m%1 + SWAP %1, %3 +%endmacro + %macro TRANSPOSE4x4B 5 SBUTTERFLY bw, %1, %2, %5 SBUTTERFLY bw, %3, %4, %5 @@ -102,12 +123,9 @@ %macro TRANSPOSE4x4PS 5 SBUTTERFLYPS %1, %2, %5 SBUTTERFLYPS %3, %4, %5 - movlhps m%5, m%1, m%3 - movhlps m%3, m%1 - SWAP %5, %1 - movlhps m%5, m%2, m%4 - movhlps m%4, m%2 - SWAP %5, %2, %3 + SBUTTERFLYPD %1, %3, %5 + SBUTTERFLYPD %2, %4, %5 + SWAP %2, %3 %endmacro %macro TRANSPOSE8x4D 9-11 @@ -260,6 +278,21 @@ SWAP %12, %15 %endmacro +%macro TRANSPOSE_8X8B 8 + %if mmsize == 8 + %error "This macro does not support mmsize == 8" + %endif + punpcklbw m%1, m%2 + punpcklbw m%3, m%4 + punpcklbw m%5, m%6 + punpcklbw m%7, m%8 + TRANSPOSE4x4W %1, %3, %5, %7, %2 + MOVHL m%2, m%1 + MOVHL m%4, m%3 + MOVHL m%6, m%5 + MOVHL m%8, m%7 +%endmacro + ; PABSW macro assumes %1 != %2, while ABS1/2 macros work in-place %macro PABSW 2 %if cpuflag(ssse3) @@ -799,12 +832,25 @@ pmaxsd %1, %2 %endmacro -%macro VBROADCASTSS 2 ; dst xmm/ymm, src m32 -%if cpuflag(avx) - vbroadcastss %1, %2 -%else ; sse - movss %1, %2 - shufps %1, %1, 0 +%macro VBROADCASTSS 2 ; dst xmm/ymm, src m32/xmm +%if cpuflag(avx2) + vbroadcastss %1, %2 +%elif cpuflag(avx) + %ifnum sizeof%2 ; avx1 register + shufps xmm%1, xmm%2, xmm%2, q0000 + %if sizeof%1 >= 32 ; mmsize>=32 + vinsertf128 %1, %1, xmm%1, 1 + %endif + %else ; avx1 memory + vbroadcastss %1, %2 + %endif +%else + %ifnum sizeof%2 ; sse register + shufps %1, %2, %2, q0000 + %else ; sse memory + movss %1, %2 + shufps %1, %1, 0 + %endif %endif %endmacro @@ -819,6 +865,21 @@ %endif %endmacro +%macro VPBROADCASTD 2 ; dst xmm/ymm, src m32/xmm +%if cpuflag(avx2) + vpbroadcastd %1, %2 +%elif cpuflag(avx) && sizeof%1 >= 32 + %error vpbroadcastd not possible with ymm on avx1. try vbroadcastss +%else + %ifnum sizeof%2 ; sse2 register + pshufd %1, %2, q0000 + %else ; sse memory + movd %1, %2 + pshufd %1, %1, 0 + %endif +%endif +%endmacro + %macro SHUFFLE_MASK_W 8 %rep 8 %if %1>=0x80 @@ -871,3 +932,79 @@ psrlq %1, 8*(%2) %endif %endmacro + +%macro MOVHL 2 ; dst, src +%ifidn %1, %2 + punpckhqdq %1, %2 +%elif cpuflag(avx) + punpckhqdq %1, %2, %2 +%elif cpuflag(sse4) + pshufd %1, %2, q3232 ; pshufd is slow on some older CPUs, so only use it on more modern ones +%else + movhlps %1, %2 ; may cause an int/float domain transition and has a dependency on dst +%endif +%endmacro + +; Horizontal Sum of Packed Single precision floats +; The resulting sum is in all elements. +%macro HSUMPS 2 ; dst/src, tmp +%if cpuflag(avx) + %if sizeof%1>=32 ; avx + vperm2f128 %2, %1, %1, (0)*16+(1) + addps %1, %2 + %endif + shufps %2, %1, %1, q1032 + addps %1, %2 + shufps %2, %1, %1, q0321 + addps %1, %2 +%else ; this form is a bit faster than the short avx-like emulation. + movaps %2, %1 + shufps %1, %1, q1032 + addps %1, %2 + movaps %2, %1 + shufps %1, %1, q0321 + addps %1, %2 + ; all %1 members should be equal for as long as float a+b==b+a +%endif +%endmacro + +; Emulate blendvps if not available +; +; src_b is destroyed when using emulation with logical operands +; SSE41 blendv instruction is hard coded to use xmm0 as mask +%macro BLENDVPS 3 ; dst/src_a, src_b, mask +%if cpuflag(avx) + blendvps %1, %1, %2, %3 +%elif cpuflag(sse4) + %ifnidn %3,xmm0 + %error sse41 blendvps uses xmm0 as default 3d operand, you used %3 + %endif + blendvps %1, %2, %3 +%else + xorps %2, %1 + andps %2, %3 + xorps %1, %2 +%endif +%endmacro + +; Emulate pblendvb if not available +; +; src_b is destroyed when using emulation with logical operands +; SSE41 blendv instruction is hard coded to use xmm0 as mask +%macro PBLENDVB 3 ; dst/src_a, src_b, mask +%if cpuflag(avx) + %if cpuflag(avx) && notcpuflag(avx2) && sizeof%1 >= 32 + %error pblendb not possible with ymm on avx1, try blendvps. + %endif + pblendvb %1, %1, %2, %3 +%elif cpuflag(sse4) + %ifnidn %3,xmm0 + %error sse41 pblendvd uses xmm0 as default 3d operand, you used %3 + %endif + pblendvb %1, %2, %3 +%else + pxor %2, %1 + pand %2, %3 + pxor %1, %2 +%endif +%endmacro |